<!DOCTYPE html>
<html lang="en-US" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>后端接口测试内容⭐⭐ | VitePress</title>
    <meta name="description" content="A VitePress site">
    <link rel="preload stylesheet" href="/notebook/assets/style.3dbfd0c2.css" as="style">
    
    <script type="module" src="/notebook/assets/app.8aaa4cbe.js"></script>
    <link rel="preload" href="/notebook/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="/notebook/assets/chunks/framework.1336c4e5.js">
    <link rel="modulepreload" href="/notebook/assets/chunks/theme.20cddc0c.js">
    <link rel="modulepreload" href="/notebook/assets/软件测试_压力测试.md.9ab44440.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-255ec12d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-ae3e3f51></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-ae3e3f51> Skip to content </a><!--]--><!----><header class="VPNav" data-v-255ec12d data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-0937f67c><div class="container" data-v-0937f67c><div class="title" data-v-0937f67c><div class="VPNavBarTitle has-sidebar" data-v-0937f67c data-v-86d1bed8><a class="title" href="/notebook/" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="/notebook/Vue.png" alt data-v-8426fc1a><!--]--><!--[-->任硕的文档<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-0937f67c><div class="curtain" data-v-0937f67c></div><div class="content-body" data-v-0937f67c><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-0937f67c><!--[--><!----><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-0937f67c data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>Java学前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/HTML+JS.html" data-v-2f2cfafc><!--[-->HTML+JS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/CSS.html" data-v-2f2cfafc><!--[-->CSS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue2+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue2+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue3+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue3+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/React.html" data-v-2f2cfafc><!--[-->React<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>软件测试</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->测试基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link active" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95.html" data-v-2f2cfafc><!--[-->压力测试<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>多线程</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-2f2cfafc><!--[-->基础篇<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%B9%B6%E5%8F%91%E5%AE%8C%E5%96%84.html" data-v-2f2cfafc><!--[-->进阶篇<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>开发工具</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/Chrome.html" data-v-2f2cfafc><!--[-->Chrome<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->IDEA基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E6%8F%92%E4%BB%B6.html" data-v-2f2cfafc><!--[-->IDEA插件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/VS%20Code.html" data-v-2f2cfafc><!--[-->VS Code<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>消息中间件</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ.html" data-v-2f2cfafc><!--[-->RabbitMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ.html" data-v-2f2cfafc><!--[-->RocketMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Kafka.html" data-v-2f2cfafc><!--[-->Kafka<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Canal.html" data-v-2f2cfafc><!--[-->Canal<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-0937f67c data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-0937f67c data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-0937f67c data-v-40855f84 data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-a7b5672a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-a7b5672a><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-0937f67c data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-255ec12d data-v-5cfd5582><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-5cfd5582><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-5cfd5582><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-5cfd5582>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-5cfd5582 data-v-18201f51><button data-v-18201f51>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-255ec12d data-v-845b8fc6><div class="curtain" data-v-845b8fc6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-845b8fc6><span class="visually-hidden" id="sidebar-aria-label" data-v-845b8fc6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Java</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%9B%86%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java集合</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Linux</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Shell.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Shell脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实用脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E8%BD%AF%E4%BB%B6%E9%83%A8%E7%BD%B2.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>软件部署</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Nginx</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%AE%9E%E6%88%98%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实战篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E9%9D%A2%E8%AF%95%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>面试篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SSM</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Maven.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Maven</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Spring.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Spring</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringMVC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringMVC</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringBatch.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringBatch</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringBoot</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%BA%94%E7%94%A8%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>应用篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E8%BF%90%E7%BB%B4&amp;%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>运维&原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringCloud</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringCloud</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/Sentinel.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Sentinel</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringSecurity</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Mybatis & MybatisPlus</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/Mybatis.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Mybatis</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/MybatisPlus.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MybatisPlus</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/JPA.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JPA</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Git & ChatGPT</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Git.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Git</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Github.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Github</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/ChatGPT.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ChatGPT</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Jenkins.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Jenkins</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Netty.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Netty</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>数据库</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MySQL</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%AE%BE%E8%AE%A1.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%90%E7%BB%B4.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL运维</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分库分表</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Redis</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis原理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis实战</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>本地缓存</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MongoDB</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E6%95%B4%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>ElasticSearch</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/1%E3%80%81ES%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/3%E3%80%81ES%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/influxdb.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>InfluxDB</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Neo4j.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Neo4j</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>高并发 & 秒杀 & 分布式</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E5%88%86%E5%B8%83%E5%BC%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式理论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式锁</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E7%A7%92%E6%9D%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>秒杀</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%8F%AF%E7%94%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高可用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%B9%B6%E5%8F%91.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高并发</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>云原生</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/Docker.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Docker</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/K8S.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>K8S</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>可视化 & 监控</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E5%8F%AF%E8%A7%86%E5%8C%96%E5%A4%A7%E5%B1%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>可视化大屏</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/Zabbix.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Zabbix</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>学前端</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>HTML+CSS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/HTML%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/CSS%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>CSS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/%E7%BD%91%E9%A1%B5%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>网页进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>JS+TS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/TypeScript.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>TS基础</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>NodeJS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Vue</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E6%96%B0%E8%AF%AD%E6%B3%95.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3新语法</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue2/Vue2%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小程序</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/uniapp.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>uniapp</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>计算机基础</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>数据结构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>操作系统</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>设计模式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>计算机网络</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/UML.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>UML</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%AE%97%E6%B3%95/LeetCode.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>LeetCode</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>项目实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>云尚办公</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E4%BA%91%E5%B0%9A%E5%8A%9E%E5%85%AC/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小兔鲜</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%871.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇1</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>地图</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>苍穹外卖</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E8%8B%8D%E7%A9%B9%E5%A4%96%E5%8D%96/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>黑马头条</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E6%94%AF%E4%BB%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>支付</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%A1%B9%E7%9B%AE%E6%8E%A8%E8%8D%90.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目推荐</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0" data-v-845b8fc6 data-v-9b797284><!----><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/team.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>团队成员</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-255ec12d data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-3f215769 data-v-ff0f39c8><div class="content" data-v-ff0f39c8><div class="outline-marker" data-v-ff0f39c8></div><div class="outline-title" data-v-ff0f39c8>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-ff0f39c8><span class="visually-hidden" id="doc-outline-aria-label" data-v-ff0f39c8> Table of Contents for current page </span><ul class="root" data-v-ff0f39c8 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _notebook_%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95_%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95" data-v-6b87e69f><div><h1 id="后端接口测试内容⭐⭐" tabindex="-1">后端接口测试内容⭐⭐ <a class="header-anchor" href="#后端接口测试内容⭐⭐" aria-label="Permalink to &quot;后端接口测试内容⭐⭐&quot;">​</a></h1><h2 id="前言" tabindex="-1">前言 <a class="header-anchor" href="#前言" aria-label="Permalink to &quot;前言&quot;">​</a></h2><p>本文主要分为两个部分：</p><p><strong>第一部分：</strong> 主要从问题出发，引入接口测试的相关内容并与前端测试进行简单对比，总结两者之前的区别与联系。但该部分只交代了怎么做和如何做？并没有解释为什么要做？</p><p><strong>第二部分：</strong> 主要介绍为什么要做接口测试，并简单总结接口持续集成和接口质量评估相关内容。</p><h2 id="第一部分⭐" tabindex="-1">第一部分⭐ <a class="header-anchor" href="#第一部分⭐" aria-label="Permalink to &quot;第一部分⭐&quot;">​</a></h2><p><strong>首先，在做接口测试的过程中，经常有后端开发会问：</strong></p><ol><li><p>后端接口都测试什么？怎么测的？</p></li><li><p>后端接口测试一遍 ，前端也测试一遍，是不是重复测试了？</p></li></ol><p>于是，为了向开发解释上述问题，普及基本的测试常识，特意梳理了接口测试的相关内容以及其与前端测试的区别，使开发团队与测试团队在测试这件上达成基本的共识，提高团队协作效率，从而更好的保证产品质量。</p><p>然后，我们试着回答上面的问题：</p><h3 id="问题1-后端接口都测试什么" tabindex="-1">问题1：后端接口都测试什么？ <a class="header-anchor" href="#问题1-后端接口都测试什么" aria-label="Permalink to &quot;问题1：后端接口都测试什么？&quot;">​</a></h3><p>回答这个问题，我们可以从接口测试活动内容的角度下手，看一下面这张图，基本反应了当前我们项目后端接口测试的主要内容：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207291625019.png" alt="image-20220729162552877" style="zoom:60%;"><h3 id="问题2-我们怎么做接口测试" tabindex="-1">问题2：我们怎么做接口测试？ <a class="header-anchor" href="#问题2-我们怎么做接口测试" aria-label="Permalink to &quot;问题2：我们怎么做接口测试？&quot;">​</a></h3><p>由于我们项目前后端调用主要是基于http协议的接口，所以测试接口时主要是通过工具或代码模拟http请求的发送与接收。工具有很多如：<code>postman</code>、<code>jmeter</code>、<code>soupUI</code>、<code>java+httpclient</code>、<code>robotframework+httplibrary</code>等。</p><h3 id="问题3-后端接口测试一遍-前端也测试一遍-是不是重复测试了" tabindex="-1">问题3：后端接口测试一遍 ，前端也测试一遍，是不是重复测试了？ <a class="header-anchor" href="#问题3-后端接口测试一遍-前端也测试一遍-是不是重复测试了" aria-label="Permalink to &quot;问题3：后端接口测试一遍 ，前端也测试一遍，是不是重复测试了？&quot;">​</a></h3><h4 id="_0、测试内容" tabindex="-1">0、测试内容 <a class="header-anchor" href="#_0、测试内容" aria-label="Permalink to &quot;0、测试内容&quot;">​</a></h4><p>回答这个问题，我们可以直接对比接口测试和app端测试活动的内容，如下图为app测试时需要覆盖或考虑内容：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207291626626.png" style="zoom:60%;"><p>从上面这两张图对比可以看出，两个测试活动中相同的部分有<strong>功能测试、边界分析测试和性能测试</strong>，其它部分由于各自特性或关注点不同需要进行特殊的测试，在此不做讨论。接下来我们针对以上三部分相同的内容再进行分析：</p><h4 id="_1、基本功能测试" tabindex="-1"><strong>1、基本功能测试</strong> <a class="header-anchor" href="#_1、基本功能测试" aria-label="Permalink to &quot;**1、基本功能测试**&quot;">​</a></h4><p>由于是针对基本业务功能进行测试，所以这部分是两种测试重合度最高的一块，开发同学通常所指的也主要是这部分的内容。</p><h4 id="_2、边界分析测试" tabindex="-1"><strong>2、边界分析测试</strong> <a class="header-anchor" href="#_2、边界分析测试" aria-label="Permalink to &quot;**2、边界分析测试**&quot;">​</a></h4><p>在基本功能测试的基础上考虑输入输出的边界条件，这部分内容也会有重复的部分（比如业务规则的边界）。但是，前端的输入输出很多时候都是提供固守的值让用户选择（如下拉框），在这种情况下测试的边界范围就非常有限，但接口测试就不存在这方面的限制，相对来说接口可以覆盖的范围更广，同样的，接口出现问题的概率也更高。</p><h4 id="_3、性能测试" tabindex="-1"><strong>3、性能测试</strong> <a class="header-anchor" href="#_3、性能测试" aria-label="Permalink to &quot;**3、性能测试**&quot;">​</a></h4><p>这个比较容易区分，虽然都需要做性能测试，但关注点确大不相同。App端性能主要关注与手机相关的特性，如手机cpu、内存、流量、fps等。而接口性能主要关注接口响应时间、并发、服务端资源的使用情况等。两种测试时的策略和方法都有很大区别，所以这部分内容是需要分开单独进行测试的，理论上来说这也是不同的部分。</p><p>综论：</p><p>1、接口测试和app测试的活动有部分重复的内容，主要集中在业务功能测试方面。除此之外，针对各自特性的测试都不一样，需要分别进行有针对性的测试，才能确保整个产品的质量。</p><p>2、接口测试可以关注于服务器逻辑验证，而UI测试可以关注于页面展示逻辑及界面前端与服务器集成验证</p><h2 id="第二部分" tabindex="-1">第二部分 <a class="header-anchor" href="#第二部分" aria-label="Permalink to &quot;第二部分&quot;">​</a></h2><h3 id="_1、什么是接口测试" tabindex="-1">1、什么是接口测试？ <a class="header-anchor" href="#_1、什么是接口测试" aria-label="Permalink to &quot;1、什么是接口测试？&quot;">​</a></h3><p>接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换，传递和控制管理过程，以及系统间的相互逻辑依赖关系等。</p><h3 id="_2、为什么要做接口测试" tabindex="-1">2、为什么要做接口测试? <a class="header-anchor" href="#_2、为什么要做接口测试" aria-label="Permalink to &quot;2、为什么要做接口测试?&quot;">​</a></h3><p>a) 如今的系统复杂度不断上升，传统的测试方法成本急剧增加且测试效率大幅下降，接口测试可以提供这种情况下的解决方案。</p><p>b) 接口测试相对容易实现自动化持续集成，且相对UI自动化也比较稳定，可以减少人工回归测试人力成本与时间，缩短测试周期，支持后端快速发版需求。接口持续集成是为什么能低成本高收益的根源。</p><p>c) 现在很多系统前后端架构是分离的，从安全层面来说：</p><p>1、只依赖前端进行限制已经完全不能满足系统的安全要求（绕过前面实在太容易）， 需要后端同样进行控制，在这种情况下就需要从接口层面进行验证。</p><p>2、前后端传输、日志打印等信息是否加密传输也是需要验证的，特别是涉及到用户的隐私信息，如身份证，银行卡等。</p><h3 id="_3、接口测试持续集成" tabindex="-1">3、接口测试持续集成 <a class="header-anchor" href="#_3、接口测试持续集成" aria-label="Permalink to &quot;3、接口测试持续集成&quot;">​</a></h3><p>对接口测试而言，持续集成自动化是核心内容，通过持自动化的手段我们才能做到低成本高收益。目前我们已经实现了接口自动化，主要应用于回归阶段，后续还需要加强自动化的程度，包括但不限于下面的内容：</p><p>a) 流程方面：在回归阶段加强接口异常场景的覆盖度，并逐步向系统测试，冒烟测试阶段延伸，最终达到全流程自动化。</p><p>b) 结果展示：更加丰富的结果展示、趋势分析，质量统计和分析等</p><p>c) 问题定位：报错信息、日志更精准，方便问题复现与定位。</p><p>d) 结果校验：加强自动化校验能力，如数据库信息校验。</p><p>e) 代码覆盖率：不断尝试由目前的黑盒向白盒下探，提高代码覆盖率。</p><p>f) 性能需求：完善性能测试体系，通过自动化的手段监控接口性能指标是否正常。</p><h3 id="_4、接口测试质量评估标准" tabindex="-1">4、接口测试质量评估标准 <a class="header-anchor" href="#_4、接口测试质量评估标准" aria-label="Permalink to &quot;4、接口测试质量评估标准&quot;">​</a></h3><p>a) 业务功能覆盖是否完整</p><p>b) 业务规则覆盖是否完整</p><p>c) 参数验证是否达到要求（边界、业务规则）</p><p>d) 接口异常场景覆盖是否完整</p><p>e) 接口覆盖率是否达到要求</p><p>f) 代码覆盖率是否达到要求</p><p>g) 性能指标是否满足要求</p><p>h) 安全指标是否满足要求</p><h1 id="系统性能" tabindex="-1">系统性能 <a class="header-anchor" href="#系统性能" aria-label="Permalink to &quot;系统性能&quot;">​</a></h1><p><strong>系统性能</strong>是对整个计算机系统的性能的研究，包括主要<strong>硬件</strong>组件和<strong>软件</strong>组件。所有数据路径上和从存储设备到应用软件上所发生的事情都包括在内，因为这些都有可能影响性能。对于分布式系统来说，这意味着多台服务器和多个应用。如果你还没有关于你的环境的一张示意图，用来显示数据的路径，赶紧找一张或者自己画一张。它可以帮助你理解所有组件的关系，并确保你不会只见树木不见森林。</p><p>系统性能的典型目标是通过<strong>减少延时</strong>和<strong>降低计算成本</strong>来改善终端用户的体验。降低成本可以通过消除低效之处、提高系统吞吐量和进行常规性能调优来实现。</p><h2 id="系统性能概念" tabindex="-1">系统性能概念 <a class="header-anchor" href="#系统性能概念" aria-label="Permalink to &quot;系统性能概念&quot;">​</a></h2><p>下面是系统性能的一些重要概念</p><h3 id="延时" tabindex="-1">延时 <a class="header-anchor" href="#延时" aria-label="Permalink to &quot;延时&quot;">​</a></h3><p><code>对于某些环境，延时是被唯一关注的性能焦点</code>。而对于其他环境，它会是除了吞吐量以外，数一数二的分析要点。</p><p>作为延时的一个例子，图 2.3 显示了如 HTTP GET 请求的网络传输，其响应时间被分成连接延时和数据传输时间两部分。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230952587.png" alt="image-20220723095204542" style="zoom:80%;"><p>延时是操作执行之前所花的等待时间。在这个例子里，操作是网络服务的数据传输请求。在这个操作发生之前，系统必须等待建立网络连接，这就是这个操作的延时。<strong>响应时间包括了延时和操作时间。</strong></p><p>因为延时可以在不同点测量，所以通常会指明延时测量的对象。例如，网站的载入时间由三个从不同点测得的不同时间组成 ：**DNS 延时、TCP 连接延时和 TCP 数据传输时间。**DNS 延时指的是整个 DNS 操作的时间，TCP 连接延时仅仅指的是初始化时间（TCP 握手）。</p><p>由于延时是一个时间上的指标，因此可能有**多种计算方法。**性能问题可以用延时来进行量化和评级，因为是用相同的单位来表达的（时间）。通过考量所能减少或移除的延时，预计的加速也可以被计算出来。这两者不能用 IOPS 指标很准确地描述出来。</p><p>时间的量级和缩写列在了表 2.1 中，可作为参考。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230949152.png" alt="image-20220723094957082" style="zoom:80%;"><p>如果可能，其他的指标也会转化为延时或者时间，这样就可以进行比较了。如果必须在 100 个网络 I/O 和 50 个磁盘 I/O 之间做出选择，怎样才能知道哪个性能更好？这是一个复杂的选择，因为其中包含了很多因素 ：<strong>网络跳数、网络丢包率和重传率、I/O 的大小、随机或顺序的 I/O、磁盘类型</strong>，等等。但是如果你比较的是 100ms 的网络 I/O 延时和 50ms 的磁盘 I/O 延时，那差别就很明显了！</p><h3 id="时间量级" tabindex="-1">时间量级 <a class="header-anchor" href="#时间量级" aria-label="Permalink to &quot;时间量级&quot;">​</a></h3><p>我们可以对时间进行量化的比较，同时最好**对时间和各种来源的延时的合理预期有本能的认识。**系统各组件的操作的时间量级差别巨大，表 2.2 中提供的延时示例，从访问 3.5GHz 的 CPU 寄存器的延时开始，阐释了各种操作时间量级的差别。表中所示的是发生单次操作的时间均值，等比放大为一个假想的系统，将 1 个 CPU 周期的 0.3ns（十亿分之一秒的三分之一 1）放大为现实生活中的 1 秒。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230950677.png" alt="image-20220723095025620" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230950160.png" alt="image-20220723095041082" style="zoom:67%;"><p>正如你所见，1 个 CPU 周期的时间是很短暂的。0.5 米差不多是你的眼睛到这个页面的距离，光线走过这段距离需要的时间大约是 1.7ns。在这段时间里，现代的 CPU 已经执行了 5 个 CPU 周期，处理了若干个指令。</p><h3 id="权衡" tabindex="-1">权衡 <a class="header-anchor" href="#权衡" aria-label="Permalink to &quot;权衡&quot;">​</a></h3><p>你应该知道某些性能权衡关系。图 2.4 展示的是<strong>好 / 快 / 便宜</strong>“择其二”的权衡关系，右图所示的是对应于 IT 项目的术语。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230951018.png" alt="image-20220723095112973" style="zoom:80%;"><p>许多 IT 项目选择了及时和成本低，留下了性能问题在以后解决。当早期的决定阻碍了性能提高的可能性时，这样的选择会变得有问题，例如，选择了非最优的存储架构，或者使用的编程语言或操作系统缺乏完善的性能分析工具。</p><p>一个常见的性能调优的权衡是在 <strong>CPU 与内存之间</strong>，因为内存能用于缓存数据结果，降低 CPU 的使用率。在有着充足 CPU 资源的现代系统里，交换可以反向进行 ：CPU 可以压缩数据来降低内存的使用。</p><h3 id="调优的影响" tabindex="-1">调优的影响 <a class="header-anchor" href="#调优的影响" aria-label="Permalink to &quot;调优的影响&quot;">​</a></h3><p>性能调优实施在越靠近工作执行的地方效果最显著。对于工作负载驱动的应用程序，这意味着调优性能的地方就在应用程序本身。表 2.3 展示了一个软件栈的例子，说明了性能调优的各种可能。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230953637.png" alt="image-20220723095311565" style="zoom:80%;"><p>对应用程序层级进行调优，可能通过<strong>消除或减少数据库查询</strong>获得很大的性能提升（例如，20 倍）。在存储设备层级进行调优，可以<strong>精简或提高存储 I/O</strong>，但是性能提升的重要部分在更高层级的操作系统栈代码，所以对存储设备层级的调优对应用程序性能的提升有限，是百分比量级的（例如，20%）。</p><p>在应用程序层级寻求性能的巨大提升，还有一个理由。如今许多环境都致力于特性和功能的快速部署，按每周或每天将软件的变更推入生产环境。 因此，应用程序的开发和测试倾向于<strong>关注正确性</strong>，在部署前留给性能测量和优化的时间很少甚至没有。之后当性能成为问题时，才会去做这些与性能相关的事情。</p><p>虽然发生在应用程序层级的调优效果最显著，但这个层级不一定是观测效果最显著的层级。数据库查询缓慢最好从其所花费的 CPU 时间、文件系统和所执行的磁盘 I/O 方面来考查。使用操作系统工具，这些都是可以观测到的。</p><h3 id="合适的层级" tabindex="-1">合适的层级 <a class="header-anchor" href="#合适的层级" aria-label="Permalink to &quot;合适的层级&quot;">​</a></h3><p>不同的公司和环境对性能有着不同的需求。你可能加入过这样的公司，其分析标准要比你之前所见过的严格得多，甚至可能听都没听过。或者是这样的公司，你觉得很基本的分析被认为很高端甚至从未使用过（这是好消息 ：事情简单轻松！）</p><p>这并不意味着某些公司做的是对的，某些做的是错的。这取决于性能技术投入的投资回报率（ROI）。拥有大型数据中心或大型云环境的组织可能会雇用一个性能工程师团队来分析所有的事情，包括内核内部和 CPU 性能计数器，并频繁使用各种跟踪工具。他们还可能对性能进行正式建模，并对未来的增长进行准确预测。对于每年在计算上有数百万花费的环境来说，雇用这样一个性能团队是值得的，因为他们进行的优化就是<strong>投资回报</strong>。小型创业公司的计算开支不大，可能只进行表面的检查，利用第三方监测方案来检查性能和提供警报。</p><h3 id="何时停止分析" tabindex="-1">何时停止分析 <a class="header-anchor" href="#何时停止分析" aria-label="Permalink to &quot;何时停止分析&quot;">​</a></h3><p>做性能分析时的一个挑战是<strong>如何知道何时停止</strong>。有这么多的工具，有这么多的东西要检查！</p><p>当我教性能课程时（最近我又开始教了），我给我的学生一个有三个原因的性能问题，我发现有些学生在找到一个原因后就停止了，有些则是两个，有些则是三个。有些学生则继续努力，试图为性能问题找到更多的原因。谁的做法是正确的？说你应该在找到所有三个原因后就停止，可能很容易，但对于现实生活中的问题，你并不知道原因的数量。</p><p><strong>这里有三种情况，你可以考虑停止分析</strong>，并提供了一些个人的例子。</p><p>当你已经解释了大部分性能问题的时候。一个 Java 应用程序消耗的 CPU 资源是原来的 3 倍。我发现的第一个问题是异常堆栈消耗了 CPU。然后我量化了这些堆栈的时间，发现它们只占整个 CPU 占用的 12%。如果这个数字接近 66%，我就可以停止分析了。但在这种情况下，在 12% 的情况下，我需要继续寻找。</p><p>当潜在的投资回报率低于分析的成本的时候。我所处理的一些性能问题可以带来每年数千万美元的收益。对于这些问题，我可以证明花几个月的时间（工程成本）进行分析是合理的。其他的性能问题，比如说微服务，可能是以数百美元计算的，甚至不值得花 1 个小时的工程时间来分析它们。例外情况可能包括 ：当我没有更好的事情可做时（这在实践中从未发生过），或者如果我怀疑这可能是日后更大问题的隐患，值得在问题扩大之前进行调试时。</p><p>当其他地方有更大的投资回报率的时候。即使前两种情况没有得到满足，其他地方有更大的投资回报时经常需要优先考虑。如果你是全职的性能工程师，根据潜在的投资回报率对不同的问题进行有选择的分析可能是一项日常工作。</p><h2 id="性能推荐的时间点" tabindex="-1">性能推荐的时间点 <a class="header-anchor" href="#性能推荐的时间点" aria-label="Permalink to &quot;性能推荐的时间点&quot;">​</a></h2><p>环境的性能特性会随着时间改变，更多的用户、新的硬件、升级的软件或固件都是变化的因素。一种环境，受限于速度 10Gb/s 的网络基础设施，当升级到 100Gb/s 时，很可能会发现磁盘或 CPU 的性能变得紧张。</p><p>性能推荐，尤其是可调优的参数值，仅仅在一段特定时间内有效。一周内从性能专家那里得到的好建议，可能到了下一周，经过一次软件或硬件升级，或者用户增多后就无效了。</p><p>在网上搜索找到的调优参数值对于某些情况可能能快速见效。但如果对于你的系统或者工作负载并不合适，它们也可能会对性能有所损害，或者合适过一次，就不再合适了，或者只是作为软件的某个 bug 修复升级之前暂时的应急措施。这和从别人的医药箱里拿药吃很像，那些药可能不适合你，或者可能已经过期，或者只适合短期服用。</p><p>如果仅仅是出于要了解有哪些参数可调以及哪些参数在过去是需要调整的，那么浏览这些性能建议是有用的。针对你的系统和工作负载，这项工作就变成了考虑这些参数是不是要调，以及调整成什么值。如果其他人不需要调整那个值，或者调整了但并未将经验分享出来，那么你有可能漏掉了重要的参数。</p><h2 id="负载与架构" tabindex="-1">负载与架构 <a class="header-anchor" href="#负载与架构" aria-label="Permalink to &quot;负载与架构&quot;">​</a></h2><p>应用程序性能差可能是因为软件配置和硬件的问题，也就是它的<strong>架构和实现</strong>问题。另外，应用程序性能差还可能是由于有太多负载，而导致了排队和长延时。负载和架构见图 2.5。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230953602.png" alt="image-20220723095348548" style="zoom:80%;"><p>如果对架构的分析显示只是工作任务在排队，处理任务没有任何问题，那么问题就可能出在施加的负载太多上。在云计算环境里，这是需要引入更多的服务器实例来处理任务的征兆。</p><p>**举个例子，**架构的问题可能是一个单线程的应用程序在单个 CPU 上忙碌，从而导致请求排队，但是其他的 CPU 却是可用且空闲的。在这个例子里，性能就被应用程序的单一线程架构限制住了。架构的另一个问题可能是一个程序的多个线程争夺一个锁，这样只有一个线程可以向前推进，而其他线程在等待。</p><p>负载的问题可能会是一个多线程程序在所有的 CPU 上都忙碌，但是请求依然排队的情况。在这个例子里，性能可能被限制于 CPU 的性能，或者说是负载超出了 CPU 所能处理的范围。</p><h2 id="缓存" tabindex="-1">缓存 <a class="header-anchor" href="#缓存" aria-label="Permalink to &quot;缓存&quot;">​</a></h2><p>**缓存被频繁使用来提高性能。**缓存是将较慢的存储层的结果存放在较快的存储层中。</p><p>把磁盘的块缓存在主存（RAM）中就是一例。</p><p>一般使用的都是多级缓存。CPU 通常利用多级硬件缓存作为主缓存（L1、L2 和L3），开始是一个非常快但是很小的缓存（L1），后续的 L2 和 L3 逐渐增加了缓存容量和访问延时。这是一个在密度和延时之间经济上的权衡。缓存的级数和大小的选择以CPU 芯片内可用空间为准，确保达到最优的性能。</p><p>一个了解缓存性能的重要指标是每个缓存的命中率—所需数据在缓存中被找到的次数（hits，命中）与总访问次数（hits+misses）的比例。</p><p><strong>命中率 = 命中次数 /（命中次数 + 失效次数）</strong></p><p><strong>命中率越高越好</strong>，更高的命中率意味着更多的数据能成功地从较快的介质中访问获得。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207230954508.png" alt="image-20220723095435470" style="zoom:80%;"><p>98% 和 99% 之间的性能差异要比 10% 和 11% 之间的性能差异大很多。由于缓存命中和失效之间的速度差异（两个存储层级），导致了这是一条非线性曲线。两个存储层级速度差异越大，曲线越陡峭。</p><h2 id="已知的未知" tabindex="-1">已知的未知 <a class="header-anchor" href="#已知的未知" aria-label="Permalink to &quot;已知的未知&quot;">​</a></h2><p>已知的已知、已知的未知、未知的未知在性能领域是很重要的概念。下面是详细的解释，并提供了系统性能分析的例子。</p><p>**已知的已知 ：**有些东西你知道。你知道你应该检查性能指标，你也知道它的当前值。举个例子，你知道你应该检查 CPU 使用率，而且你也知道当前均值是10%。</p><p>**已知的未知 ：**有些东西你知道你不知道。你知道你可以检查一个指标或者判断一个子系统是否存在，但是你还没去做。举个例子，你知道你能用剖析检查是什么致使 CPU 忙碌，但你还没去做这件事。</p><p>**未知的未知 ：**有些东西你不知道你不知道。举个例子，你可能不知道设备中断可以消耗大量 CPU 资源，因此你对此并不做检查。在性能领域，“<code>你知道的越多，你不知道的也就越多</code>”。这和学习系统是一样的原理：你了解的越多，你就能意识到未知的未知越多，然后这些未知的未知会变成你可以去查看的已知的未知。</p><h1 id="性能指标" tabindex="-1">性能指标 <a class="header-anchor" href="#性能指标" aria-label="Permalink to &quot;性能指标&quot;">​</a></h1><p>性能指标是由系统、应用程序，或者其他工具选定的统计数据，用于测量感兴趣的活动。性能指标用于性能分析和监测，可以由命令行提供数据，也可以由可视化工具提供图表。</p><h2 id="吞吐量" tabindex="-1">吞吐量 <a class="header-anchor" href="#吞吐量" aria-label="Permalink to &quot;吞吐量&quot;">​</a></h2><p>在了解<code>qps</code>、<code>tps</code>、<code>rt</code>、并发数之前，首先我们应该明确一个系统的吞吐量到底代表什么含义，一般来说，系统吞吐量指的是系统的抗压、负载能力，<code>代表一个系统每秒钟能承受的最大用户访问量</code>。</p><p>一个系统的吞吐量通常由<code>qps</code>（tps）、并发数来决定，每个系统对这两个值都有一个相对极限值，只要某一项达到最大值，系统的吞吐量就上不去了。</p><h2 id="qps每秒处理查询的次数" tabindex="-1">QPS每秒处理查询的次数 <a class="header-anchor" href="#qps每秒处理查询的次数" aria-label="Permalink to &quot;QPS每秒处理查询的次数&quot;">​</a></h2><p>系统每秒内处理查询的次数</p><p><code>Queries Per Second</code>，每秒查询数，即是每秒能够响应的查询次数，注意这里的查询是指用户发出请求到服务器做出响应成功的次数，简单理解可以认为查询=请求<code>request</code>。</p><p><code>qps</code>=每秒钟<code>request</code>数量</p><p>Hits Per Second - HPS：用户每秒点击次数，也就是每秒向后台发送的请求次数</p><h2 id="tps每秒处理的事务数" tabindex="-1">TPS每秒处理的事务数 <a class="header-anchor" href="#tps每秒处理的事务数" aria-label="Permalink to &quot;TPS每秒处理的事务数&quot;">​</a></h2><p><code>Transactions Per Second</code> 的缩写，每秒处理的事务数。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时，收到服务器响应后结束计时，以此来计算使用的时间和完成的事务个数。</p><p>针对单接口而言，<code>TPS</code>可以认为是等价于<code>QPS</code>的，比如访问一个页面<code>/index.html</code>，是一个<code>TPS</code>，而访问/index.html页面可能请求了3次服务器比如<code>css</code>、<code>js</code>、<code>index</code>接口，产生了3个<code>QPS</code>。</p><h2 id="rt响应时间" tabindex="-1">RT响应时间 <a class="header-anchor" href="#rt响应时间" aria-label="Permalink to &quot;RT响应时间&quot;">​</a></h2><blockquote><p>响应时间，用户从客户端发起一个请求开始计算，到客户端接收到服务端的响应结束，整个过程所耗费的时间。</p></blockquote><ul><li><p><code>Response Time</code>缩写，简单理解为系统从输入到输出的时间间隔，宽泛的来说，他代表从客户端发起请求到服务端接受到请求并响应所有数据的时间差。一般取平均响应时间。</p></li><li><p>MaxRT：最大响应时间，指用户发出请求到服务端返回响应的最大时间。</p></li><li><p>MiniRT：最少响应时间，指用户发出请求到服务端返回响应的最少时间。</p></li><li><p>90%响应时间：将所有用户的响应时间进行升序排序，取 90 % 的位置。</p></li></ul><h2 id="并发数" tabindex="-1">并发数 <a class="header-anchor" href="#并发数" aria-label="Permalink to &quot;并发数&quot;">​</a></h2><p>简而言之，系统能同时处理的请求/事务数量。</p><p>计算方式</p><p>QPS<code>= 并发数 /</code>RT<code>或者 并发数=</code>QPS<code>*</code>RT</p><p>举个栗子：</p><p>假设公司每天早上9点到10点1个小时内都有员工要上厕所，公司有3600个员工，平均每个员工上厕所时间为10分钟，我们来计算一下。</p><p><code>QPS</code> = 3600/(60*60) 1</p><p><code>RT</code> = 10*60 600秒</p><p><code>并发数</code> = 1 * 600 600</p><p>这样就意味着如果想达到最好的蹲坑体验，公司需要600个坑位来满足员工需求，否则的话上厕所就要排队等待了。</p><h2 id="性能思考" tabindex="-1">性能思考 <a class="header-anchor" href="#性能思考" aria-label="Permalink to &quot;性能思考&quot;">​</a></h2><p>按照 <code>QPS</code> = <code>并发数</code> / <code>RT</code> 公式，假设我们现在是单线程的场景，那么 <code>QPS</code> 公式应该是这样：<code>QPS</code>= 1/RT，实际上 <code>RT</code> 应该= <code>CPU time</code> + <code>CPU wait time</code>，如果将线程数提高到2，那么<code>QPS</code> = 2/(CPU time + CPU wait time)，那么是否意味着我们只要单纯提高线程数就能提高QPS呢？</p><h2 id="最佳线程数计算" tabindex="-1">最佳线程数计算 <a class="header-anchor" href="#最佳线程数计算" aria-label="Permalink to &quot;最佳线程数计算&quot;">​</a></h2><p>假设CPU time是49ms，CPU wait time是200ms，那么QPS=1000ms/249ms=4.01，这里200ms的wait时间我们可以认为CPU一直处于等待状态啥也没干，理论上来说200ms还可以接受200/49≈4个请求，不考虑上下文切换和其他开销的话，可以认为总线程数=(200+49)/49=5，如果再考虑上CPU多核和利用率的问题，我们大致可以认为：最佳线程数=RT/CPU Time * CPU核心数 * CPU利用率</p><p>那么最大 <code>QPS</code>公式推导为：</p><p>最大 <code>QPS</code> = 最佳线程数<em>单线程 <code>QPS</code>=（RT/CPU Time * CPU核心数 * CPU利用率）</em>（1/RT) = CPU核心数*CPU利用率/CPU time</p><p>那么这样是否意味着我们只要不停增加CPU核心数就能无限提高QPS呢</p><h2 id="阿姆达尔定律amdahl" tabindex="-1">阿姆达尔定律Amdahl <a class="header-anchor" href="#阿姆达尔定律amdahl" aria-label="Permalink to &quot;阿姆达尔定律Amdahl&quot;">​</a></h2><p><img src="https://mmbiz.qpic.cn/mmbiz_png/0OzaL5uW2aPzN4vtT0ia5LtL2JMArXEDFh26VYR3FpeeibTzII5DdRibuPzAE7cPSKzBA08viaqZJ4iaG0qQWAKQ0tA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>G.M.Amdahl在1967年提出了Amdahl’s law，针对并行处理的scalability给出了一个模型，指出使用并行处理的提速由问题的可并行的部分所决定。我们可以简单理解为程序通过额外的计算资源，理论上能获得的加速值。</p><p>par为并行计算所占的比例，p为并行处理节点个数</p><p>假设你想从望京去顺义，坐一辆车需要3小时，虽然现在有3辆车，你也不能1小时就到。这里无法并行，所有Par=0%，p=3，加速比还是等于1，并没有提高速度。</p><h2 id="古斯塔夫森定律gustafson" tabindex="-1">古斯塔夫森定律Gustafson <a class="header-anchor" href="#古斯塔夫森定律gustafson" aria-label="Permalink to &quot;古斯塔夫森定律Gustafson&quot;">​</a></h2><p><img src="https://mmbiz.qpic.cn/mmbiz_png/0OzaL5uW2aPzN4vtT0ia5LtL2JMArXEDFw6ibV0ichHyUugoAynjicyADichwQagiaSbhyIlScdlMAYvvTVn96Xce88Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>斯塔夫森定律又被称为扩展的 <code>加速比</code>(scaled speedup)，他说明处理器个数、串行比例和加速比之间的关系，只是和阿姆达尔定律侧重角度有所不同。</p><p>按照阿姆达尔定律和QPS计算公式，在<code>CPUtime</code> 和 <code>CPU</code> 利用率不变的情况下，增加 <code>CPU核心数</code>就能增加最大<code>QPS</code>，在 <code>par</code> 不为0即并行的时候，增加并行数量 p 就能提升效率，但是实际上随着请求数量的增加，带来大量的上下文的切换、gc和锁变化。qps更高，产生对象越多，<code>gc</code>越频繁，cpu time和利用率都受到影响，尤其在串行的时候，锁自旋、自适应、偏向等等也成为影响par的因素。</p><h2 id="性能测试关注点" tabindex="-1">性能测试关注点 <a class="header-anchor" href="#性能测试关注点" aria-label="Permalink to &quot;性能测试关注点&quot;">​</a></h2><p>为了提升达到最好的性能，我们需要不断的进行性能测试，调整小城池大小，找到最合适的参数来达到提高性能的目的。性能测试关注点：</p><ul><li>吞吐量：每秒钟系统能处理的请求数、任务数。</li><li>响应时间：服务处理一个请求或一个任务的耗时。</li><li>错误率：一批请求中结果出过错的请求所占比例。</li></ul><h2 id="性能指标观测⭐⭐" tabindex="-1">性能指标观测⭐⭐ <a class="header-anchor" href="#性能指标观测⭐⭐" aria-label="Permalink to &quot;性能指标观测⭐⭐&quot;">​</a></h2><h3 id="网络配置如何看" tabindex="-1">网络配置如何看？ <a class="header-anchor" href="#网络配置如何看" aria-label="Permalink to &quot;网络配置如何看？&quot;">​</a></h3><p>要想知道网络的配置和状态，我们可以使用 <code>ifconfig</code> 或者 <code>ip</code> 命令来查看。</p><p>这两个命令功能都差不多，不过它们属于不同的软件包，<code>ifconfig</code> 属于 <code>net-tools</code> 软件包，<code>ip</code> 属于 <code>iproute2</code> 软件包，我的印象中 <code>net-tools</code> 软件包没有人继续维护了，而 <code>iproute2</code> 软件包是有开发者依然在维护，所以更推荐你使用 <code>ip</code> 工具。</p><p>学以致用，那就来使用这两个命令，来查看网口 <code>eth0</code> 的配置等信息：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208091717712.png" alt="image-20220809171751617" style="zoom:67%;"><p>虽然这两个命令输出的格式不尽相同，但是输出的内容基本相同，比如都包含了 IP 地址、子网掩码、MAC 地址、网关地址、MTU 大小、网口的状态以及网路包收发的统计信息，下面就来说说这些信息，它们都与网络性能有一定的关系。</p><p>第一，网口的连接状态标志。其实也就是表示对应的网口是否连接到交换机或路由器等设备，如果 <code>ifconfig</code> 输出中看到有 <code>RUNNING</code>，或者 <code>ip</code> 输出中有 <code>LOWER_UP</code>，则说明物理网路是连通的，如果看不到，则表示网口没有接网线。</p><p>第二，MTU 大小。默认值是 <code>1500</code> 字节，其作用主要是限制网络包的大小，如果 IP 层有一个数据报要传，而且数据帧的长度比链路层的 MTU 还大，那么 IP 层就需要进行分片，即把数据报分成干片，这样每一片就都小于 MTU。事实上，每个网络的链路层 MTU 可能会不一样，所以你可能需要调大或者调小 MTU 的数值。</p><p>第三，网口的 IP 地址、子网掩码、MAC 地址、网关地址。这些信息必须要配置正确，网络功能才能正常工作。</p><p>第四，网路包收发的统计信息。通常有网络收发的字节数、包数、错误数以及丢包情况的信息，如果 <code>TX</code>（发送） 和 <code>RX</code>（接收） 部分中 errors、dropped、overruns、carrier 以及 collisions 等指标不为 0 时，则说明网络发送或者接收出问题了，这些出错统计信息的指标意义如下：</p><ul><li><em>errors</em> 表示发生错误的数据包数，比如校验错误、帧同步错误等；</li><li><em>dropped</em> 表示丢弃的数据包数，即数据包已经收到了 Ring Buffer（这个缓冲区是在内核内存中，更具体一点是在网卡驱动程序里），但因为系统内存不足等原因而发生的丢包；</li><li><em>overruns</em> 表示超限数据包数，即网络接收/发送速度过快，导致 Ring Buffer 中的数据包来不及处理，而导致的丢包，因为过多的数据包挤压在 Ring Buffer，这样 Ring Buffer 很容易就溢出了；</li><li><em>carrier</em> 表示发生 carrirer 错误的数据包数，比如双工模式不匹配、物理电缆出现问题等；</li><li><em>collisions</em> 表示冲突、碰撞数据包数；</li></ul><p><code>ifconfig</code> 和 <code>ip</code> 命令只显示的是网口的配置以及收发数据包的统计信息，而看不到协议栈里的信息，那接下来就来看看如何查看协议栈里的信息。</p><hr><h3 id="socket-信息如何查看" tabindex="-1">socket 信息如何查看？ <a class="header-anchor" href="#socket-信息如何查看" aria-label="Permalink to &quot;socket 信息如何查看？&quot;">​</a></h3><p>我们可以使用 <code>netstat</code> 或者 <code>ss</code>，这两个命令查看 socket、网络协议栈、网口以及路由表的信息。</p><p>虽然 <code>netstat</code> 与 <code>ss</code> 命令查看的信息都差不多，但是如果在生产环境中要查看这类信息的时候，尽量不要使用 <code>netstat</code> 命令，因为它的性能不好，在系统比较繁忙的情况下，如果频繁使用 <code>netstat</code> 命令则会对性能的开销雪上加霜，所以更推荐你使用性能更好的 <code>ss</code> 命令。</p><p>从下面这张图，你可以看到这两个命令的输出内容：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208091718129.png" alt="image-20220809171817063" style="zoom:67%;"><p>可以发现，输出的内容都差不多， 比如都包含了 socket 的状态（<em>State</em>）、接收队列（<em>Recv-Q</em>）、发送队列（<em>Send-Q</em>）、本地地址（<em>Local Address</em>）、远端地址（<em>Foreign Address</em>）、进程 PID 和进程名称（<em>PID/Program name</em>）等。</p><p>接收队列（<em>Recv-Q</em>）和发送队列（<em>Send-Q</em>）比较特殊，在不同的 socket 状态。它们表示的含义是不同的。</p><p>当 socket 状态处于 <code>Established</code>时：</p><ul><li><em>Recv-Q</em> 表示 socket 缓冲区中还没有被应用程序读取的字节数；</li><li><em>Send-Q</em> 表示 socket 缓冲区中还没有被远端主机确认的字节数；</li></ul><p>而当 socket 状态处于 <code>Listen</code> 时：</p><ul><li><em>Recv-Q</em> 表示全连接队列的长度；</li><li><em>Send-Q</em> 表示全连接队列的最大长度；</li></ul><p>在 TCP 三次握手过程中，当服务器收到客户端的 SYN 包后，内核会把该连接存储到半连接队列，然后再向客户端发送 SYN+ACK 包，接着客户端会返回 ACK，服务端收到第三次握手的 ACK 后，内核会把连接从半连接队列移除，然后创建新的完全的连接，并将其增加到全连接队列 ，等待进程调用 <code>accept()</code> 函数时把连接取出来。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208091718862.png" alt="image-20220809171839778" style="zoom:50%;"><p>也就说，全连接队列指的是服务器与客户端完了 TCP 三次握手后，还没有被 <code>accept()</code> 系统调用取走连接的队列。</p><p>那对于协议栈的统计信息，依然还是使用 <code>netstat</code> 或 <code>ss</code>，它们查看统计信息的命令如下：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208091719923.png" alt="image-20220809171900847" style="zoom:67%;"><p><code>ss</code> 命令输出的统计信息相比 <code>netsat</code> 比较少，<code>ss</code> 只显示已经连接（<em>estab</em>）、关闭（<em>closed</em>）、孤儿（<em>orphaned</em>） socket 等简要统计。</p><p>而 <code>netstat</code> 则有更详细的网络协议栈信息，比如上面显示了 TCP 协议的主动连接（<em>active connections openings</em>）、被动连接（<em>passive connection openings</em>）、失败重试（<em>failed connection attempts</em>）、发送（<em>segments send out</em>）和接收（<em>segments received</em>）的分段数量等各种信息。</p><hr><h3 id="网络吞吐率和-pps-如何查看" tabindex="-1">网络吞吐率和 PPS 如何查看？ <a class="header-anchor" href="#网络吞吐率和-pps-如何查看" aria-label="Permalink to &quot;网络吞吐率和 PPS 如何查看？&quot;">​</a></h3><p>可以使用 <code>sar</code> 命令当前网络的吞吐率和 PPS，用法是给 <code>sar</code> 增加 <code>-n</code> 参数就可以查看网络的统计信息，比如</p><ul><li>sar -n DEV，显示网口的统计数据；</li><li>sar -n EDEV，显示关于网络错误的统计数据；</li><li>sar -n TCP，显示 TCP 的统计数据</li></ul><p>比如，我通过 <code>sar</code> 命令获取了网口的统计信息：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208091719973.png" alt="image-20220809171936903" style="zoom:67%;"><p>它们的含义：</p><ul><li><code>rxpck/s</code> 和 <code>txpck/s</code> 分别是接收和发送的 PPS，单位为包 / 秒。</li><li><code>rxkB/s</code> 和 <code>txkB/s</code> 分别是接收和发送的吞吐率，单位是 KB/ 秒。</li><li><code>rxcmp/s</code> 和 <code>txcmp/s</code> 分别是接收和发送的压缩数据包数，单位是包 / 秒。</li></ul><p>对于带宽，我们可以使用 <code>ethtool</code> 命令来查询，它的单位通常是 <code>Gb/s</code> 或者 <code>Mb/s</code>，不过注意这里小写字母 <code>b</code> ，表示比特而不是字节。我们通常提到的千兆网卡、万兆网卡等，单位也都是比特（<em>bit</em>）。如下你可以看到， eth0 网卡就是一个千兆网卡：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">$ ethtool eth0 | grep Speed</span></span>
<span class="line"><span style="color:#A6ACCD;">  Speed: 1000Mb/s</span></span></code></pre></div><hr><h3 id="连通性和延时如何查看" tabindex="-1">连通性和延时如何查看？ <a class="header-anchor" href="#连通性和延时如何查看" aria-label="Permalink to &quot;连通性和延时如何查看？&quot;">​</a></h3><p>要测试本机与远程主机的连通性和延时，通常是使用 <code>ping</code> 命令，它是基于 ICMP 协议的，工作在网络层。</p><p>比如，如果要测试本机到 <code>192.168.12.20</code> IP 地址的连通性和延时：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208091719968.png" alt="image-20220809171922889" style="zoom:67%;"><p>显示的内容主要包含 <code>icmp_seq</code>（ICMP 序列号）、<code>TTL</code>（生存时间，或者跳数）以及 <code>time</code> （往返延时），而且最后会汇总本次测试的情况，如果网络没有丢包，<code>packet loss</code> 的百分比就是 0。</p><p>不过，需要注意的是，<code>ping</code> 不通服务器并不代表 HTTP 请求也不通，因为有的服务器的防火墙是会禁用 ICMP 协议的。</p><h1 id="性能监控" tabindex="-1">性能监控 <a class="header-anchor" href="#性能监控" aria-label="Permalink to &quot;性能监控&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&amp;mid=2247495751&amp;idx=1&amp;sn=dcaa50097b5cac9f85b292df20280e20&amp;chksm=fbcf9d7fccb814699550645081b8776c12dc369d0b18bf3342ac8795d0b1bb6e94151e49ef76&amp;mpshare=1&amp;scene=23&amp;srcid=0511fdLZpWUw8EeMF54TGdLm&amp;sharer_sharetime=1652228096399&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">48张图|手摸手教你性能监控、压测和调优 (qq.com)</a></p><h2 id="jconsole" tabindex="-1">jconsole <a class="header-anchor" href="#jconsole" aria-label="Permalink to &quot;jconsole&quot;">​</a></h2><p>jconsole 和 jvisualvm 是 Java JDK 的两个小工具，用来监控内存泄漏、跟踪垃圾回收、执行时的内存情况、对 CPU 进行分析、线程的分析。都可以通过命令行启动，而且可以监控本地和远程应用。而 jvisualvm 是升级版的 jconsole。我们先来看下 jconsole 的使用。</p><p>首先用 cmd 命令行的方式启动 jconsole。</p><h3 id="启动-jconsole" tabindex="-1">启动 jconsole <a class="header-anchor" href="#启动-jconsole" aria-label="Permalink to &quot;启动 jconsole&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112010233.png" alt="image-20220511201027195" style="zoom:80%;"><h3 id="选择监控哪个应用" tabindex="-1">选择监控哪个应用 <a class="header-anchor" href="#选择监控哪个应用" aria-label="Permalink to &quot;选择监控哪个应用&quot;">​</a></h3><p>然后选择，看准名字选择</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112006720.png" alt="image-20220511200626668" style="zoom:80%;"><h3 id="结果概览" tabindex="-1">结果概览 <a class="header-anchor" href="#结果概览" aria-label="Permalink to &quot;结果概览&quot;">​</a></h3><p>从监控界面上有 6 个菜单，首先看到的是概览功能，上面有堆内存使用量、线程数、类的使用情况、CPU 占用率，都是用趋势图来表示的，能很方便的看出当前性能的概览。</p><p>注意：这些监控都是实时的，用jmeter进行多线程访问测试，发现能正常波动。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112009958.png" alt="image-20220511200924901" style="zoom:80%;"><h3 id="内存" tabindex="-1">内存 <a class="header-anchor" href="#内存" aria-label="Permalink to &quot;内存&quot;">​</a></h3><p>下面是内存的使用情况，可以从下图中看到有个下拉框，里面可以选择不同的内存维度，然后下面的图标和柱状图也会跟着选择的维度而展示不同。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112014612.png" alt="image-20220511201440553" style="zoom:80%;"><p>下面是线程的使用情况，可以看到线程峰值和活动线程的总数量，目前看到的峰值是59，活动线程数是 57。下半部分可以看到具体是哪些线程，以及线程的堆栈信息，非常详细。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112015659.png" alt="image-20220511201518598" style="zoom:80%;"><p>下面是线程的使用情况，可以看到线程峰值和活动线程的总数量，目前看到的峰值是59，活动线程数是 57。下半部分可以看到具体是哪些线程，以及线程的堆栈信息，非常详细。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112015883.png" alt="image-20220511201542820" style="zoom:80%;"><h3 id="类" tabindex="-1">类 <a class="header-anchor" href="#类" aria-label="Permalink to &quot;类&quot;">​</a></h3><p>下面是类的加载和卸载情况，已加载类总数是 10679，而已卸载的类是 1 个，所以当前已加装当前类的总数是 10679 - 1 = 10678 个。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112016027.png" alt="image-20220511201615972" style="zoom:80%;"><h3 id="vm-概要" tabindex="-1">VM 概要 <a class="header-anchor" href="#vm-概要" aria-label="Permalink to &quot;VM 概要&quot;">​</a></h3><p>我们再来看下VM（虚拟机）的情况。如下图所示，可以看到虚拟机情况，线程、类、堆的概要信息，以及 VM 的参数，是不是很方便呀~</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112016038.png" alt="image-20220511201647981" style="zoom:80%;"><h3 id="mbean-信息" tabindex="-1">MBean 信息 <a class="header-anchor" href="#mbean-信息" aria-label="Permalink to &quot;MBean 信息&quot;">​</a></h3><p>接下来我们来看下 MBean 信息。对于 MBean，可能很多同学不知道是啥，下面做个解释：</p><p>MBean就是一种规范的JavaBean，通过集成和实现一套标准的Bean接口，这种叫MBean。MBean可以用来干嘛？就是可以有一套JDK级别的对外的服务接口。比如，你写了一个JVM允许状态辅助查询的Bean,你希望别人下载一个Jconsole就可以看到你写的杰作。那你就可以考虑用MBean规范来实现。很多垃圾收集器算法Bean就这么干的（说的就是这个类sun.management.MemoryImpl）。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112017744.png" alt="image-20220511201711692" style="zoom:80%;"><h2 id="jvisualvm" tabindex="-1">jvisualvm <a class="header-anchor" href="#jvisualvm" aria-label="Permalink to &quot;jvisualvm&quot;">​</a></h2><p>jvisualvm 比 jconsole 更强大，界面展示的信息更丰富。还可以安装插件，太赞了。</p><p><code>现在jdk里不带了，要自己下载，还是英文版本</code></p><h3 id="启动-jvisualvm-和概述" tabindex="-1">启动 jvisualvm 和概述 <a class="header-anchor" href="#启动-jvisualvm-和概述" aria-label="Permalink to &quot;启动 jvisualvm 和概述&quot;">​</a></h3><p>启动方式和 jconsole 一样，也是通过 cmd 命令行启动。还是选择微服务，然后选择第一个菜单栏：概述。可以看到 JVM 的版本，启动参数等信息。</p><h3 id="监视" tabindex="-1">监视 <a class="header-anchor" href="#监视" aria-label="Permalink to &quot;监视&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112045920.png" alt="image-20220511204553854" style="zoom:80%;"><h3 id="线程" tabindex="-1">线程 <a class="header-anchor" href="#线程" aria-label="Permalink to &quot;线程&quot;">​</a></h3><p>再来查下线程的情况。可以看到有 5 种状态的线程：</p><ul><li>运行：正在运行的线程。</li><li>休眠：休眠状态的线程。</li><li>等待：等待执行的线程。</li><li>驻留：线程里面的空闲线程。</li><li>监视：阻塞的线程，正在等待锁。</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112047845.png" alt="image-20220511204713784" style="zoom:80%;"><h3 id="抽样器" tabindex="-1">抽样器 <a class="header-anchor" href="#抽样器" aria-label="Permalink to &quot;抽样器&quot;">​</a></h3><p>另外我们也可以抽样器对 CPU 或内存进行抽样。如下图所示，对内存进行抽样。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112047722.png" alt="image-20220511204731667" style="zoom:80%;"><h3 id="插件的使用" tabindex="-1">插件的使用 <a class="header-anchor" href="#插件的使用" aria-label="Permalink to &quot;插件的使用&quot;">​</a></h3><h4 id="安装visual-gc-插件" tabindex="-1">安装Visual GC 插件 <a class="header-anchor" href="#安装visual-gc-插件" aria-label="Permalink to &quot;安装Visual GC 插件&quot;">​</a></h4><p>安装步骤：工具-&gt;插件-&gt;可用插件-&gt;Visual GC-&gt;安装。安装完成后，重启就可以使用插件功能了。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112048990.png" alt="image-20220511204826932" style="zoom:80%;"><p>安装完成后，就可以看到</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112048591.png" alt="image-20220511204841540" style="zoom:80%;"><p>下图是实时监控垃圾回收的情况。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112048824.png" alt="image-20220511204857763" style="zoom:80%;"><h1 id="性能测试" tabindex="-1">性能测试 <a class="header-anchor" href="#性能测试" aria-label="Permalink to &quot;性能测试&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&amp;mid=2247495751&amp;idx=1&amp;sn=dcaa50097b5cac9f85b292df20280e20&amp;chksm=fbcf9d7fccb814699550645081b8776c12dc369d0b18bf3342ac8795d0b1bb6e94151e49ef76&amp;mpshare=1&amp;scene=23&amp;srcid=0511fdLZpWUw8EeMF54TGdLm&amp;sharer_sharetime=1652228096399&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">48张图|手摸手教你性能监控、压测和调优 (qq.com)</a></p><h2 id="网关的性能测试" tabindex="-1">网关的性能测试 <a class="header-anchor" href="#网关的性能测试" aria-label="Permalink to &quot;网关的性能测试&quot;">​</a></h2><p>现在我想对 Passjava 系统的 question 微服务的接口进行一个压测，该如何进行呢？</p><p>首先我们来看下 passjava 的架构是怎么样的，如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112059430.png" alt="image-20220511205907380" style="zoom:80%;"><p>客户端分为手机端和 PC 端，http 请求先经过 API Gateway，然后再转发到 question 微服务。其中涉及到了中间件：Gateway 网关。</p><p>我们来对 Gateway 网关进行压力测试。</p><p>网关的端口号是 8060，我们配置下 JMeter。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112059762.png" alt="image-20220511205924716" style="zoom:80%;"><p>配置每秒发送 200 个请求，一直循环执行，直到手动停止压测。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112059928.png" alt="image-20220511205938892" style="zoom:80%;"><p>可以看下执行结果，吞吐量在 2422 个每秒，还是比较高的。</p><p>吞吐量：2422/s 。</p><p>90% 响应时间：142 毫秒。</p><p>99% 响应时间：281 毫秒。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112059667.png" alt="image-20220511205954618" style="zoom:80%;"><p>我们再来看看垃圾回收的情况，Eden 区垃圾回收用时 2.7 s，用时太长了吧，看看这里怎么能优化下。</p><p>通常的优化方向是增大新生代堆内存配置。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112100094.png" alt="image-20220511210009027" style="zoom:80%;"><h2 id="对微服务的性能测试" tabindex="-1">对微服务的性能测试 <a class="header-anchor" href="#对微服务的性能测试" aria-label="Permalink to &quot;对微服务的性能测试&quot;">​</a></h2><p>根据上面的架构原理图，我们知道客户端请求都是经过 Gateway 转发了一次的，如果我们想单独看下微服务的性能该怎么测试呢？下面我来演示下如何测试 passjava-question 微服务的性能。</p><p>首先需要在 passjava-question 微服务中添加一个测试方法：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112058803.png" alt="image-20220511205843763" style="zoom:80%;"><p>有两种方式测试这个 api 是否添加正确。</p><p>第一种用 postman 测试下这个请求是否能正确响应，返回 “test” 则表示响应正确。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112058149.png" alt="image-20220511205822096" style="zoom:80%;"><p>第二种通过浏览器进行测试。浏览器地址栏输入以下链接后，回车，看下浏览器窗口是否显示 “test”，是则表示响应正确。</p><p>然后我们需要用 Jmeter 压测工具来测试这个微服务下的 api 的性能究竟如何。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112057996.png" alt="image-20220511205744948" style="zoom:80%;"><p>吞吐量：3542/s 。</p><p>90% 响应时间：100 毫秒。</p><p>99% 响应时间：152 毫秒。</p><h2 id="对网关-微服务的性能测试" tabindex="-1">对网关+微服务的性能测试 <a class="header-anchor" href="#对网关-微服务的性能测试" aria-label="Permalink to &quot;对网关+微服务的性能测试&quot;">​</a></h2><p>如果我们想对这个整个请求链路进行性能测试该怎么做？</p><p>首先请求需要先经过网关，然后由网关转发到微服务。在之前的文章中，我已经将网关配置好了，所以要想通过网关转发到 test 请求，只需要对请求路径稍作修改即可，如下所示：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8060</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">api</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">question</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">v1</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">question</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">test</span></span></code></pre></div><p>然后在浏览器输入该网址，返回 “test” 即表示响应正确。</p><p>然后我们还是用 Jmeter 压测工具测试下 test api 的性能。测试结果如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112056702.png" alt="image-20220511205624653" style="zoom:80%;"><p>从结果可以看到：</p><p>吞吐量：982/s 。</p><p>90% 响应时间：437 毫秒。</p><p>99% 响应时间：790毫秒。</p><p>这里做个横向对比：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112056385.png" alt="image-20220511205644340" style="zoom:80%;"><p>说明微服务 api 经过网关转发一次后，性能至少下降了一半。可以得出结果：中间件越多，性能损失越大，大部分损失都是网络交互导致的。可以通过增强网络通信质量来减少网络的延迟。</p><h2 id="对数据库查询进行优化" tabindex="-1">对数据库查询进行优化 <a class="header-anchor" href="#对数据库查询进行优化" aria-label="Permalink to &quot;对数据库查询进行优化&quot;">​</a></h2><p>一般情况下，出现性能问题更多的是业务中查询数据库的耗时。接下来看下如何优化数据的查询。</p><p>下面是一个查询问题列表的 api：通过问题类型 type 字段过滤问题列表。api 路径如下：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">11000</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">question</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">v1</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">question</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">list</span><span style="color:#89DDFF;">?</span><span style="color:#A6ACCD;">type</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">5</span></span></code></pre></div><p>这个 api 的代码如下，很容易看懂。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112053805.png" alt="image-20220511205307757" style="zoom:80%;"><p>我们加些测试代码：统计查询数据库的耗时。如下所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112053576.png" alt="image-20220511205331524" style="zoom:80%;"><p>然后重启 passjava-question 服务，再次测试这个 api，耗时 43 ms</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112053595.png" alt="image-20220511205352548" style="zoom:80%;"><p>怎么对查询进行优化呢？很容易想到加索引，我们来试下加在 question 表加索引后的效果。给 type 字段加上普通索引，如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112054241.png" alt="image-20220511205408184" style="zoom:80%;"><p>我们再来看下加了索引后的耗时情况：耗时 18 ms，确实比之前的 43 ms 快了很多。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112054249.png" alt="image-20220511205428199" style="zoom:80%;"><h2 id="优化垃圾回收" tabindex="-1">优化垃圾回收 <a class="header-anchor" href="#优化垃圾回收" aria-label="Permalink to &quot;优化垃圾回收&quot;">​</a></h2><p>我们可以通过 jvisulavm工具查看垃圾回收的情况，Eden 区频繁发生 GC，短时间（1分钟）内共造成了 480 次 stop the world。另外从压测工具中也可以看到，吞吐量为 275/s。</p><p>原因是 Eden 区的内存分配得太小了，只有 32 M，我们来调大一点。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112052684.png" alt="image-20220511205204604" style="zoom:67%;"><h3 id="增大-eden-区大小" tabindex="-1">增大 Eden 区大小 <a class="header-anchor" href="#增大-eden-区大小" aria-label="Permalink to &quot;增大 Eden 区大小&quot;">​</a></h3><p>通过在 IDEA 工具中配置以下参数，调整堆内存最大为 1024 M，新生代内存为 512 M。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">Xmx1024m </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">Xms1024m </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">Xmn512m</span></span></code></pre></div><p>然后可以观察到在相当长的短时间（1分钟）内只进行了 92 次垃圾回收，说明垃圾回收的频率降低了。应用程序的性能也提升了。另外从压测工具中也可以看到，吞吐量为 347/s，吞吐量也有较大提升。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112051755.png" alt="image-20220511205131666" style="zoom:80%;"><h2 id="总结" tabindex="-1">总结 <a class="header-anchor" href="#总结" aria-label="Permalink to &quot;总结&quot;">​</a></h2><p>本文通过压测工具 Jmeter 讲解压测如何实施，然后用性能监控工具 jconsole 和 jvisualvm 来监控 Java 应用程序的性能，以及如何用工具来优化开源项目 passjava 的性能，并且非常详细地介绍了每一步以及执行结果，通过对比的方式，更加清晰地知道如何做性能优化。</p><p>下面是对系统性能的常规优化手段：</p><ul><li>中间件较多时，优化网络通信质量。</li><li>数据库查询耗时时，需要对查询进行优化，比如添加索引。</li><li>模板的渲染速度，可以通过设置模板缓存。</li><li>静态资源的获取，可以通过 Nginx 动静分离来解决。（下期再讲）</li><li>日志太多，需要减少不必要的打 log 操作。</li></ul><h1 id="ab压力测试" tabindex="-1">ab压力测试 <a class="header-anchor" href="#ab压力测试" aria-label="Permalink to &quot;ab压力测试&quot;">​</a></h1><p><a href="https://blog.csdn.net/u011415782/article/details/78501799" target="_blank" rel="noreferrer">(41条消息) CentOS7 ab压力测试安装与解释_u011415782的专栏-CSDN博客_centos 安装ab</a></p><p><a href="https://developer.aliyun.com/article/709108?spm=a2c6h.14164896.0.0.75dd735bcbQthB" target="_blank" rel="noreferrer">AB-阿里云开发者社区 (aliyun.com)</a></p><p>Apache Benchmark(简称ab) 是Apache安装包中自带的压力测试工具 ，简单易用</p><p>安装</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">yum -y install httpd-tools</span></span></code></pre></div><p>ab测试的命令参数：ab 或 ab -help</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">ab </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">可选的参数选项</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;"> 需要进行压力测试的url</span></span></code></pre></div><p>可选参数</p><p>此外，我们再根据上面的用法介绍界面来详细了解每个参数选项的作用。</p><ul><li>-n 即requests，用于<strong>指定压力测试总共的执行次数(重要)</strong>。</li><li>-c 即concurrency，用于<strong>指定的并发数(重要)</strong>。</li><li>-t 即timelimit，等待响应的最大时间(单位：秒)。</li><li>-b 即windowsize，TCP发送/接收的缓冲大小(单位：字节)。</li><li>-p 即postfile，发送POST请求时需要上传的文件，此外还必须设置-T参数。</li><li>-u 即putfile，发送PUT请求时需要上传的文件，此外还必须设置-T参数。</li><li>-T 即content-type，用于设置Content-Type请求头信息，例如：application/x-www-form-urlencoded，默认值为text/plain。</li><li>-v 即verbosity，指定打印帮助信息的冗余级别。</li><li>-w 以HTML表格形式打印结果。</li><li>-i 使用HEAD请求代替GET请求。</li><li>-x 插入字符串作为table标签的属性。</li><li>-y 插入字符串作为tr标签的属性。</li><li>-z 插入字符串作为td标签的属性。</li><li>-C 添加cookie信息，例如：&quot;Apache=1234&quot;(可以重复该参数选项以添加多个)。</li><li>-H 添加任意的请求头，例如：&quot;Accept-Encoding: gzip&quot;，请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)。</li><li>-A 添加一个基本的网络认证信息，用户名和密码之间用英文冒号隔开。</li><li>-P 添加一个基本的代理认证信息，用户名和密码之间用英文冒号隔开。</li><li>-X 指定使用的和端口号，例如:&quot;126.10.10.3:88&quot;。</li><li>-V 打印版本号并退出。</li><li>-k 使用HTTP的KeepAlive特性。</li><li>-d 不显示百分比。</li><li>-S 不显示预估和警告信息。</li><li>-g 输出结果信息到gnuplot格式的文件中。</li><li>-e 输出结果信息到CSV格式的文件中。</li><li>-r 指定接收到错误信息时不退出程序。</li><li>-h 显示用法信息，其实就是ab -help。</li></ul><h2 id="ab的使用" tabindex="-1">ab的使用 <a class="header-anchor" href="#ab的使用" aria-label="Permalink to &quot;ab的使用&quot;">​</a></h2><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;"> 模拟并发请求</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">次，总共请求</span><span style="color:#F78C6C;">10000</span><span style="color:#A6ACCD;">次</span></span>
<span class="line"><span style="color:#A6ACCD;">ab </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">c </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">n </span><span style="color:#F78C6C;">10000</span><span style="color:#A6ACCD;"> 待测试网站（建议完整路径）</span></span></code></pre></div><p>例子</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">ab </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">c </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">n </span><span style="color:#F78C6C;">5000</span><span style="color:#A6ACCD;"> http:</span><span style="color:#89DDFF;">//</span><span style="color:#F78C6C;">192.168.1.107</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8080</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">getAll</span></span>
<span class="line"><span style="color:#A6ACCD;">ab </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">c </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">n </span><span style="color:#F78C6C;">5000</span><span style="color:#A6ACCD;"> http:</span><span style="color:#89DDFF;">//</span><span style="color:#F78C6C;">192.168.1.107</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8080</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">getById</span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">5</span></span></code></pre></div><p>内容解释(重要)</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220223183636494.png" alt="image-20220223183636494" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220223190731363.png" alt="image-20220223190731363" style="zoom:67%;"><p>访问量过大时，会出现无法访问的情况</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">ab </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">c </span><span style="color:#F78C6C;">10000</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">n </span><span style="color:#F78C6C;">50000</span><span style="color:#A6ACCD;"> http:</span><span style="color:#89DDFF;">//</span><span style="color:#F78C6C;">192.168.1.107</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8080</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">getById</span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">5</span></span></code></pre></div><p>出现问题：socket: Too many open files (24)</p><p>简单解释：并发访问量过大 服务器拒绝访问，理论上通过系统配置，可以有更好的承受能力</p><h2 id="注意事项" tabindex="-1">注意事项 <a class="header-anchor" href="#注意事项" aria-label="Permalink to &quot;注意事项&quot;">​</a></h2><ul><li>测试机与被测试机要分开</li><li><strong>不要对线上的服务器做压力测试</strong></li><li>观察测试工具ab所在机器，以及被测试的前端机的CPU、内存、网络等都不超过最高限度的75%</li></ul><h1 id="jmh方法测试⭐⭐" tabindex="-1">JMH方法测试⭐⭐ <a class="header-anchor" href="#jmh方法测试⭐⭐" aria-label="Permalink to &quot;JMH方法测试⭐⭐&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&amp;mid=2247497533&amp;idx=1&amp;sn=d3006585823f12d06d91a45572623928&amp;chksm=fc2c4b35cb5bc223b3f666cb57ca0588b23029dee636909914f6ef53f5176906f6a68f7083c3&amp;mpshare=1&amp;scene=23&amp;srcid=0415atVRusxiIhlcRjiOwxOw&amp;sharer_sharetime=1650024558451&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">别再写 main 方法测试了，太 Low！这才是专业 Java 测试方法！ (qq.com)</a></p><p><a href="https://blog.csdn.net/ZYC88888/article/details/113741316" target="_blank" rel="noreferrer">https://blog.csdn.net/ZYC88888/article/details/113741316</a></p><p><a href="https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&amp;mid=2247529973&amp;idx=2&amp;sn=1a8a2d6f097971073adaa875d0fe2b7b&amp;chksm=ebd54ad9dca2c3cfcb24757948ab12498052a639b0e49934a4514decb7a5c70c8bac2029ea7b&amp;mpshare=1&amp;scene=23&amp;srcid=1030ASdZU5RZ23YfDRH95OBE&amp;sharer_sharetime=1667105118966&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">测试和性能监控神器 JMH &amp; Arthas (qq.com)</a></p><h2 id="jmh-初见" tabindex="-1">JMH 初见 <a class="header-anchor" href="#jmh-初见" aria-label="Permalink to &quot;JMH 初见&quot;">​</a></h2><p>if 快还是 switch 快？HashMap 的初始化 size 要不要指定，指定之后性能可以提高多少？各种序列化方法哪个耗时更短？</p><p>无论出自何种原因需要进行性能评估，量化指标总是必要的。在大部分场合，简单地回答谁快谁慢是远远不够的，如何将程序性能量化呢？这就需要我们的主角 JMH 登场了！</p><p>基于JMH可以对很多工具和框架进行测试，比如日志框架性能对比、BeanCopy性能对比 等，更多的example可以参考官方给出的<a href="https://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/" target="_blank" rel="noreferrer">JMH samples</a></p><blockquote><p>JMH，全称 Java Microbenchmark Harness (微基准测试框架），是专门用于Java代码微基准测试的一套测试工具API，是由 OpenJDK/Oracle 官方发布的工具。何谓 Micro Benchmark 呢？简单地说就是在 method 层面上的 benchmark，精度可以精确到微秒级。</p></blockquote><h3 id="jmh-注意点" tabindex="-1">JMH 注意点 <a class="header-anchor" href="#jmh-注意点" aria-label="Permalink to &quot;JMH 注意点&quot;">​</a></h3><p>Java的基准测试需要注意的几个点：</p><blockquote><ul><li>测试前需要预热。</li><li>防止无用代码进入测试方法中。</li><li>并发测试。</li><li>测试结果呈现。</li></ul></blockquote><h3 id="jmh的使用场景" tabindex="-1">JMH的使用场景 <a class="header-anchor" href="#jmh的使用场景" aria-label="Permalink to &quot;JMH的使用场景&quot;">​</a></h3><p>这里面我们需要注意的是，JMH所测试的方法约简单越好，依赖越少越好，最适合的场景就是，测试两个集合put，get性能，例如ArrayList与LinkedList的对比等</p><blockquote><ol><li>定量分析某个热点函数的优化效果</li><li>想定量地知道某个函数需要执行多长时间，以及执行时间和输入变量的相关性</li><li>对比一个函数的多种实现方式</li></ol></blockquote><h3 id="依赖引入" tabindex="-1">依赖引入 <a class="header-anchor" href="#依赖引入" aria-label="Permalink to &quot;依赖引入&quot;">​</a></h3><p>因为 JMH 是 JDK9 自带的，如果是 JDK9 之前的版本需要加入如下依赖（目前 JMH 的最新版本为 <code>1.35</code>）：</p><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.openjdk.jmh</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">jmh-core</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">1.35</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.openjdk.jmh</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">jmh-generator-annprocess</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">1.35</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h3 id="创建一个-jmh-测试类" tabindex="-1">创建一个 JMH 测试类 <a class="header-anchor" href="#创建一个-jmh-测试类" aria-label="Permalink to &quot;创建一个 JMH 测试类&quot;">​</a></h3><p>接下来，创建一个 JMH 测试类，用来判断 <code>+</code> 和 <code>StringBuilder.append()</code> 两种字符串拼接哪个耗时更短</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AverageTime</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Warmup</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Measurement</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Threads</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">4</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Fork</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">State</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> Scope</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Benchmark</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">OutputTimeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NANOSECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">StringConnectTest</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Param</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">10</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">50</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">100</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> length</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testStringAdd</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Blackhole</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">blackhole</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> length</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            a </span><span style="color:#89DDFF;">+=</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">        blackhole</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">consume</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">a</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testStringBuilderAdd</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Blackhole</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">blackhole</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">StringBuilder</span><span style="color:#A6ACCD;"> sb </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StringBuilder</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> length</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            sb</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">append</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">i</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">        blackhole</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">consume</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">sb</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">toString</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">throws</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RunnerException</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">StringConnectTest</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">result</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">result.json</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">resultFormat</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ResultFormatType</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">JSON</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">opt</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>其中需要测试的方法用 <code>@Benchmark</code> 注解标识，这些注解的具体含义将在下面介绍。在 main() 函数中，首先对测试用例进行配置，使用 Builder 模式配置测试，将配置参数存入 Options 对象，并使用 Options 对象构造 Runner 启动测试。另外大家可以看下官方提供的 jmh 示例 demo：<a href="http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/" target="_blank" rel="noreferrer">官方Demo</a></p><h3 id="结果分析查看" tabindex="-1">结果分析查看 <a class="header-anchor" href="#结果分析查看" aria-label="Permalink to &quot;结果分析查看&quot;">​</a></h3><blockquote><p>将生成的result.json加载到上面的网站：<a href="http://deepoove.com/jmh-visual-chart/" target="_blank" rel="noreferrer">http://deepoove.com/jmh-visual-chart/</a></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212081645478.png" alt="image-20221208164550369" style="zoom:80%;"><h3 id="执行基准测试" tabindex="-1">执行基准测试 <a class="header-anchor" href="#执行基准测试" aria-label="Permalink to &quot;执行基准测试&quot;">​</a></h3><p>准备工作做好了，接下来，运行代码，等待片刻，测试结果就出来了，下面对结果做下简单说明：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212081637022.png" alt="image-20221208163753915" style="zoom:80%;"><p>该部分为<strong>测试的基本信息</strong>，比如使用的 Java 路径，预热代码的迭代次数，测量代码的迭代次数，使用的线程数量，测试的统计单位等。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212081639671.png" alt="image-20221208163913598" style="zoom:80%;"><p>该部分为每一次热身中的性能指标，预热测试不会作为最终的统计结果。预热的目的是<strong>让 JVM 对被测代码进行足够多的优化</strong>，比如，在预热后，被测代码应该得到了充分的 JIT 编译和优化。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212081639834.png" alt="image-20221208163959742" style="zoom:80%;"><p>该部分显示测量迭代的情况，每一次迭代都显示了当前的执行速率，即一个操作所花费的时间。在进行 5 次迭代后，进行统计，在本例中，length 为 100 的情况下 <code>testStringBuilderAdd</code> 方法的平均执行花费时间为 <code>819.329 ns</code>，误差为 <code>72.698 ns</code>。最后的测试结果如下所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212081640194.png" alt="image-20221208164037103" style="zoom:80%;"><p>结果表明，在拼接字符次数越多的情况下，<code>StringBuilder.append()</code> 的性能就更好。</p><h3 id="生成-jar-包执行" tabindex="-1">生成 jar 包执行 <a class="header-anchor" href="#生成-jar-包执行" aria-label="Permalink to &quot;生成 jar 包执行&quot;">​</a></h3><p>对于一些小测试，直接用上面的方式写一个 main 函数手动执行就好了。</p><p>对于大型的测试，需要测试的时间比较久、线程数比较多，加上测试的服务器需要，一般要放在 Linux 服务器里去执行。</p><p>JMH 官方提供了生成 jar 包的方式来执行，我们需要在 maven 里增加一个 plugin，具体配置如下：</p><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">plugins</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">plugin</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.apache.maven.plugins</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">maven-shade-plugin</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">2.4.1</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">executions</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">execution</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">phase</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">package</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">phase</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">goals</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">goal</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">shade</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">goal</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">goals</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">configuration</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">finalName</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">jmh-demo</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">finalName</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">transformers</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">transformer</span></span>
<span class="line"><span style="color:#89DDFF;">                                </span><span style="color:#C792EA;">implementation</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">org.apache.maven.plugins.shade.resource.ManifestResourceTransformer</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                            </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">mainClass</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.openjdk.jmh.Main</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">mainClass</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                        </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">transformer</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">transformers</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">configuration</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">execution</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">executions</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">plugin</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">plugins</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><p>接着执行 maven 的命令生成可执行 jar 包并执行：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mvn clean install</span></span>
<span class="line"><span style="color:#A6ACCD;">java -jar target/jmh-demo.jar StringConnectTest</span></span></code></pre></div><h2 id="注解介绍" tabindex="-1">注解介绍 <a class="header-anchor" href="#注解介绍" aria-label="Permalink to &quot;注解介绍&quot;">​</a></h2><p>下面我们来详细介绍一下相关的注解</p><p><code>JMH</code>是一个jar包，它和单元测试框架<code>JUnit</code>非常的像，可以通过注解进行一些基础配置。这部分配置有很多是可以通过main方法的<code>OptionsBuilder</code>进行设置的。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221414094.png" alt="image-20220722141407007" style="zoom:67%;"><h3 id="benchmark" tabindex="-1">@Benchmark <a class="header-anchor" href="#benchmark" aria-label="Permalink to &quot;@Benchmark&quot;">​</a></h3><p><code>声明一个public方法为基准测试方法</code>。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testFor</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> sum </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1000000</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        sum </span><span style="color:#89DDFF;">+=</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="benchmarkmode-重点" tabindex="-1">@BenchmarkMode(重点) <a class="header-anchor" href="#benchmarkmode-重点" aria-label="Permalink to &quot;@BenchmarkMode(重点)&quot;">​</a></h3><blockquote><p>通过JMH我们可以轻松的测试出某个接口的吞吐量、平均执行时间等指标的数据。假设我想测试方法的<strong>平均耗时</strong>，那么可以使用@BenchmarkMode注解指定测试维度为Mode.AverageTime。此注解用来指定基准测试类型，对应Mode选项，用来修饰类和方法都可以。这里的value，是一个数组，可以配置多个统计维度。比如：</p></blockquote><p>@BenchmarkMode({Throughput,Mode.AverageTime})。统计的就是吞吐量和平均执行时间两个指标。</p><p>微基准测试类型。<strong>JMH</strong> 提供了以下几种类型进行支持：</p><table><thead><tr><th style="text-align:left;">类型</th><th style="text-align:left;">描述</th></tr></thead><tbody><tr><td style="text-align:left;">Throughput</td><td style="text-align:left;">整体吞吐量，比如QPS，单位时间内的调用量等。</td></tr><tr><td style="text-align:left;">AverageTime</td><td style="text-align:left;">平均耗时，指的是每次执行的平均时间。如果这个值很小不好辨认，可以把统计的单位时间调小一点。</td></tr><tr><td style="text-align:left;">SampleTime</td><td style="text-align:left;">随机<code>取样</code>。</td></tr><tr><td style="text-align:left;">SingleShotTime</td><td style="text-align:left;">如果你想要测试仅仅一次的性能，比如第一次初始化花了多长时间，就可以使用这个参数，其实和传统的main方法没有什么区别。</td></tr><tr><td style="text-align:left;">All</td><td style="text-align:left;">所有模式</td></tr></tbody></table><p>可以注释在方法级别，也可以注释在类级别，</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">All</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">LinkedListIterationBenchMark</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">({</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SingleShotTime</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">m</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>我们拿平均时间，看一下一个大体的执行结果：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Result </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">com.github.xjjdog.tuning.BenchmarkTest.shift</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">2.068</span><span style="color:#A6ACCD;"> ±</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">99.9</span><span style="color:#A6ACCD;">%</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.038</span><span style="color:#A6ACCD;"> ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op </span><span style="color:#89DDFF;">[</span><span style="color:#A6ACCD;">Average</span><span style="color:#89DDFF;">]</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">min</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> avg</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> max</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2.059</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2.068</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2.083</span><span style="color:#89DDFF;">),</span><span style="color:#A6ACCD;"> stdev </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.010</span></span>
<span class="line"><span style="color:#A6ACCD;">  CI </span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">99.9</span><span style="color:#A6ACCD;">%</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;">: </span><span style="color:#89DDFF;">[</span><span style="color:#F78C6C;">2.030</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2.106</span><span style="color:#89DDFF;">]</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">assumes normal distribution</span><span style="color:#89DDFF;">)</span></span></code></pre></div><p>由于我们声明的时间单位是纳秒，本次shift方法的平均响应时间就是2.068纳秒。</p><p>我们也可以看下最终的耗时时间。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Benchmark            Mode  Cnt  Score   Error  Units</span></span>
<span class="line"><span style="color:#A6ACCD;">BenchmarkTest</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">div    avgt    </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">2.072</span><span style="color:#A6ACCD;"> ± </span><span style="color:#F78C6C;">0.053</span><span style="color:#A6ACCD;">  ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span>
<span class="line"><span style="color:#A6ACCD;">BenchmarkTest</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">shift  avgt    </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">2.068</span><span style="color:#A6ACCD;"> ± </span><span style="color:#F78C6C;">0.038</span><span style="color:#A6ACCD;">  ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span></code></pre></div><p>由于是平均数，这里的Error值的是误差的意思（或者波动）。</p><p>可以看到，在衡量这些指标的时候，都有一个时间维度，它就是通过**@OutputTimeUnit**注解进行配置的。</p><p>这个就比较简单了，它指明了基准测试结果的时间类型。可用于类或者方法上。一般选择秒、毫秒、微秒，纳秒那是针对的速度非常快的方法。</p><p>举个例子，<code>@BenchmarkMode(Mode.Throughput)</code>和<code>@OutputTimeUnit(TimeUnit.MILLISECONDS)</code>进行组合，代表的就是每毫秒的吞吐量。</p><p>如下面的关于吞吐量的结果，就是以毫秒计算的。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Benchmark             Mode  Cnt       Score       Error   Units</span></span>
<span class="line"><span style="color:#A6ACCD;">BenchmarkTest</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">div    thrpt    </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">482999.685</span><span style="color:#A6ACCD;"> ±  </span><span style="color:#F78C6C;">6415.832</span><span style="color:#A6ACCD;">  ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ms</span></span>
<span class="line"><span style="color:#A6ACCD;">BenchmarkTest</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">shift  thrpt    </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">480599.263</span><span style="color:#A6ACCD;"> ± </span><span style="color:#F78C6C;">20752.609</span><span style="color:#A6ACCD;">  ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ms</span></span></code></pre></div><p><code>OutputTimeUnit</code>注解同样可以修饰类或者方法，通过更改时间级别，可以获取更加易读的结果。</p><h3 id="warmup-重点" tabindex="-1">@Warmup(重点) <a class="header-anchor" href="#warmup-重点" aria-label="Permalink to &quot;@Warmup(重点)&quot;">​</a></h3><p>这个单词的意思就是预热，<code>iterations = 3</code>就是指预热轮数。</p><p>为了数据准确，我们可能需要让testGson方法做下热身运动。如在方法中创建GsonParser对象，预热可以避免首次创建GsonParser时因多了类加载的耗时而导致测试结果不准备的情况。jvm使用JIT即时编译器，一定的预热次数可让JIT对testGson方法的调用链路完成编译，去掉解释执行对测试结果的影响。</p><p>@Warmup注解用于配置预热参数。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Warmup</span><span style="color:#89DDFF;">(</span></span>
<span class="line"><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span></code></pre></div><p>我们不止一次提到预热，<code>warmup</code>这个注解，可以用在类或者方法上，进行预热配置。可以看到，它有几个配置参数。</p><ul><li><code>timeUnit</code>：时间的单位，默认的单位是秒。</li><li><code>iterations</code>：预热阶段的迭代数。</li><li><code>time</code>：每次预热的时间。</li><li><code>batchSize</code>：批处理大小，指定了每次操作调用几次方法。</li></ul><p>上面的注解，意思是对代码预热总计5秒（迭代5次，每次一秒） 。预热过程的测试数据，是不记录测量结果的。</p><p>我们可以看一下它执行的效果：</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># Warmup</span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;"> iterations</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> s each</span></span>
<span class="line"><span style="color:#A6ACCD;"># </span><span style="color:#C792EA;">Warmup</span><span style="color:#A6ACCD;"> Iteration   </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.281</span><span style="color:#A6ACCD;"> ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ns</span></span>
<span class="line"><span style="color:#A6ACCD;"># </span><span style="color:#C792EA;">Warmup</span><span style="color:#A6ACCD;"> Iteration   </span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.376</span><span style="color:#A6ACCD;"> ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ns</span></span>
<span class="line"><span style="color:#A6ACCD;"># </span><span style="color:#C792EA;">Warmup</span><span style="color:#A6ACCD;"> Iteration   </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0.483</span><span style="color:#A6ACCD;"> ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ns</span></span></code></pre></div><p>一般来说，基准测试都是针对的比较小的、执行速度相对较快的代码块。这些代码有很大的可能被编译、内联，在编码的时候保持方法的精简，对JIT也是有好的。</p><p>说到预热，就不得不提一下在分布式环境下的服务预热。在对服务节点进行发布的时候，通常也会有预热过程，逐步放量到相应的服务节点，直到服务达到最优状态。如下图所示，负载均衡负责这个放量过程，一般是根据百分比进行放量。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221416939.png" alt="image-20220722141638859" style="zoom:67%;"><h3 id="measurement-重点" tabindex="-1">@Measurement(重点) <a class="header-anchor" href="#measurement-重点" aria-label="Permalink to &quot;@Measurement(重点)&quot;">​</a></h3><p>假设我想测量方法五次，那么可以使用<code>@Measurement</code>注解。</p><p>正式度量计算的轮数。</p><ul><li><code>iterations</code> 进行测试的轮次</li><li><code>time</code> 每轮进行的时长</li><li><code>timeUnit</code>时长单位</li></ul><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">({</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SingleShotTime</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Measurement</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">m</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p><code>Measurement</code>和<code>Warmup</code>的参数是一样的。不同于预热，它指的是真正的迭代次数。</p><p>我们能够从日志中看到这个执行过程：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> Measurement: </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;"> iterations</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> s each</span></span>
<span class="line"><span style="color:#A6ACCD;">Iteration   </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">: </span><span style="color:#F78C6C;">1646.000</span><span style="color:#A6ACCD;"> ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span>
<span class="line"><span style="color:#A6ACCD;">Iteration   </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">: </span><span style="color:#F78C6C;">1243.000</span><span style="color:#A6ACCD;"> ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span>
<span class="line"><span style="color:#A6ACCD;">Iteration   </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">: </span><span style="color:#F78C6C;">1273.000</span><span style="color:#A6ACCD;"> ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span>
<span class="line"><span style="color:#A6ACCD;">Iteration   </span><span style="color:#F78C6C;">4</span><span style="color:#A6ACCD;">: </span><span style="color:#F78C6C;">1395.000</span><span style="color:#A6ACCD;"> ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span>
<span class="line"><span style="color:#A6ACCD;">Iteration   </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">: </span><span style="color:#F78C6C;">1423.000</span><span style="color:#A6ACCD;"> ns</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">op</span></span></code></pre></div><p>虽然经过预热之后，代码都能表现出它的最优状态，但一般和实际应用场景还是有些出入的。如果你的测试机器性能很高，或者你的测试机资源利用已经达到了极限，都会影响测试结果的数值。通常情况下，我都会在测试的时候，给机器充足的资源，保持一个稳定的环境。在分析结果的时候，也更加关注不同实现方式的<strong>性能差异</strong>，而不是测试数据本身。</p><h3 id="threads" tabindex="-1">@Threads <a class="header-anchor" href="#threads" aria-label="Permalink to &quot;@Threads&quot;">​</a></h3><p><code>fork</code>是面向进程的，而<code>Threads</code>是面向线程的。指定了这个注解以后，将会开启并行测试。</p><p>如果配置了 Threads.MAX ，则使用和处理机器核数相同的线程数。</p><p><code>@Threads</code>注解用于指定使用多少个线程来执行基准测试方法，如果使用<code>@Threads</code>指定线程数为<code>2</code>，那么每次测量都会创建两个线程来执行基准测试方法。</p><p>每个进程中的测试线程。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Threads</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Threads</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MAX</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">LinkedListIterationBenchMark</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>如果@Measurement注解指定time为1s，基准测试方法的执行耗时为1s，那么如果只使用单个线程，一次测量只会执行一次基准测试方法，如果使用10个线程，一次测量就能执行10次基准测试方法。</p><h3 id="fork-重点" tabindex="-1">@Fork(重点) <a class="header-anchor" href="#fork-重点" aria-label="Permalink to &quot;@Fork(重点)&quot;">​</a></h3><p>面向进程</p><p>fork的值一般设置成1，表示只使用一个进程进行测试；如果这个数字大于1，表示会启用新的进程进行测试；但如果设置成0，程序依然会运行，不过这样是在用户的JVM进程上运行的，可以看下下面的提示，但不推荐这么做。</p><p>进行 fork 的次数。如果 fork 数是3的话，则 JMH 会 fork 出3个进程来进行测试。</p><p><code>@Fork</code>用于指定<code>fork</code>出多少个子进程来执行同一基准测试方法。</p><p>假设我们不需要多个进程，那么 可以使用<code>@Fork</code>指定为进程数为1。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">({</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SingleShotTime</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Fork</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">m</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>在这里分享一个小技巧。其实fork注解有一个参数叫做<code>jvmArgsAppend</code>，我们可以通过它传递一些JVM的参数。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#A6ACCD;">Fork</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">value </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> jvmArgsAppend </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">-Xmx2048m</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">-server</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">-XX:+AggressiveOpts</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">})</span></span></code></pre></div><p>在平常的测试中，也可以适当增加fork数，来减少测试的误差。</p><h3 id="outputtimeunit" tabindex="-1">@OutputTimeUnit <a class="header-anchor" href="#outputtimeunit" aria-label="Permalink to &quot;@OutputTimeUnit&quot;">​</a></h3><p>OutputTimeUnit注解用于指定输出的方法执行耗时的单位。如果方法执行耗时为秒级别，为了便于 观察结果，我们可以使用@OutputTimeUnit指定输出的耗时时间单位为秒；如果方法执行耗时为毫秒级别，为了便于观察结果，<code>我们可以使用@OutputTimeUnit指定输出的耗时时间单位为毫秒，否则使用默认的秒做单位</code>，会输出10的负几次方这样的数字，不太直观。</p><p>基准测试结果的时间类型。一般选择秒、毫秒、微秒。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">OutputTimeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">LinkedListIterationBenchMark</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="param-重点" tabindex="-1">@Param(重点) <a class="header-anchor" href="#param-重点" aria-label="Permalink to &quot;@Param(重点)&quot;">​</a></h3><p>属性级注解，<code>@Param</code> 可以用来指定某项参数的多种情况。</p><p>特别适合用来<code>测试一个函数在不同的参数输入的情况下的性能</code>。</p><p>使用@Param注解可指定基准方法执行参数，@Param注解只能指定String类型的值，可以是一个数组，参数值将在运行期间按给定顺序遍历。假设@Param注解指定了多个参数值，那么JMH会为每个参数值进行一次测量。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">// 指定参数有三个值</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Param</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">3</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> jsonStr</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>代码样例如下：</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AverageTime</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">OutputTimeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NANOSECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Warmup</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Measurement</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Fork</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">State</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Scope</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Benchmark</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">JMHSample_27_Params</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Param</span><span style="color:#89DDFF;">({</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">31</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">65</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">101</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">103</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> arg</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Param</span><span style="color:#89DDFF;">({</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">0</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">4</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">8</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">16</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">32</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">})</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> certainty</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">boolean</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">bench</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> BigInteger</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">valueOf</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">arg</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">isProbablePrime</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">certainty</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">throws</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RunnerException</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">JMHSample_27_Params</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#89DDFF;">               </span><span style="color:#676E95;font-style:italic;">// Use this to selectively constrain/override parameters</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">//.param(&quot;arg&quot;, &quot;41&quot;, &quot;42&quot;) </span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">opt</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>值得注意的是，如果你设置了非常多的参数，这些参数将执行多次，通常会运行很长时间。比如参数1 M个，参数2 N个，那么总共要执行M*N次。</p><p>下面是一个执行结果的截图。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221438963.png" alt="image-20220722143833806" style="zoom:80%;"><h3 id="setup、-teardown" tabindex="-1">@Setup、@TearDown <a class="header-anchor" href="#setup、-teardown" aria-label="Permalink to &quot;@Setup、@TearDown&quot;">​</a></h3><p>方法级注解，这个注解的作用就是我们需要在测试之前进行一些<strong>准备工作</strong>，比如对一些数据的初始化之类的。</p><p>方法级注解，这个注解的作用就是我们需要在测试之后进行一些<strong>结束工作</strong>，比如关闭线程池，数据库连接等的，主要用于资源的回收等。</p><p>和单元测试框架JUnit类似，用于基准测试前的初始化动作， @TearDown 用于基准测试后的动作，来做一些全局的配置。</p><p>这两个注解，同样有一个Level值，标明了方法运行的时机，它有三个取值。</p><ul><li><strong>Trial</strong>：默认的级别。也就是Benchmark级别。</li><li><strong>Iteration</strong>：每次迭代都会运行。</li><li><strong>Invocation</strong>：每次方法调用都会运行，这个是粒度最细的。</li></ul><h3 id="state-重点" tabindex="-1">@State(重点) <a class="header-anchor" href="#state-重点" aria-label="Permalink to &quot;@State(重点)&quot;">​</a></h3><p>当使用<code>@Setup</code>参数的时候，<code>必须在类上加这个参数，不然会提示无法运行</code>。</p><p>就比如我上面的例子中，就必须设置<code>state</code>。</p><p><code>State</code> 用于声明某个类是一个“状态”，然后接受一个 Scope 参数用来表示该状态的共享范围。因为很多 benchmark 会需要一些表示状态的类，JMH 允许你把这些类以依赖注入的方式注入到 benchmark 函数里。Scope 主要分为三种。</p><ol><li>Thread: 该状态为每个线程独享。</li><li>Group: 该状态为同一个组里面所有线程共享。</li><li>Benchmark: 该状态在所有线程间共享。</li></ol><p>在<code>JMHSample04DefaultState</code>测试文件中，演示了变量<code>x</code>的默认作用范围是Thread，关键代码如下：</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">State</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Scope</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Thread</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">JMHSample_04_DefaultState</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">double</span><span style="color:#A6ACCD;"> x </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> Math</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">PI</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">measure</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        x</span><span style="color:#89DDFF;">++;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="compilercontrol" tabindex="-1">@CompilerControl <a class="header-anchor" href="#compilercontrol" aria-label="Permalink to &quot;@CompilerControl&quot;">​</a></h3><p>这可以说是一个非常有用的功能了。</p><p>Java中方法调用的开销是比较大的，尤其是在调用量非常大的情况下。拿简单的getter/setter方法来说，这种方法在Java代码中大量存在。我们在访问的时候，就需要创建相应的栈帧，访问到需要的字段后，再弹出栈帧，恢复原程序的执行。</p><p>如果能够把这些对象的访问和操作，纳入到目标方法的调用范围之内，就少了一次方法调用，速度就能得到提升，这就是方法内联的概念。如图所示，代码经过JIT编译之后，效率会有大的提升。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221436455.png" alt="image-20220722143646369" style="zoom:67%;"><p>这个注解可以用在类或者方法上，能够控制方法的编译行为，常用的有3种模式。</p><p>强制使用内联（INLINE），禁止使用内联（DONT_INLINE），甚至是禁止方法编译（EXCLUDE）等。</p><h2 id="启动运行和结果展示" tabindex="-1">启动运行和结果展示 <a class="header-anchor" href="#启动运行和结果展示" aria-label="Permalink to &quot;启动运行和结果展示&quot;">​</a></h2><h3 id="结果展示" tabindex="-1">结果展示 <a class="header-anchor" href="#结果展示" aria-label="Permalink to &quot;结果展示&quot;">​</a></h3><p>使用JMH测试的结果，可以二次加工，进行图形化展示。结合图表数据，更加直观。通过运行时，指定输出的格式文件，即可获得相应格式的性能测试结果。</p><p>比如下面这行代码，就是指定输出JSON格式的数据。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Options opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> new OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">resultFormat</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ResultFormatType</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">JSON</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">build</span><span style="color:#89DDFF;">();</span></span></code></pre></div><p>自动生成该文件</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202210302120672.png" alt="image-20221030212040518" style="zoom:80%;"><p>JMH支持以下5种格式的结果：</p><ul><li><strong>TEXT</strong> 导出文本文件。</li><li><strong>CSV</strong> 导出csv格式文件。</li><li><strong>SCSV</strong> 导出scsv等格式的文件。</li><li><strong>JSON</strong> 导出成json文件。</li><li><strong>LATEX</strong> 导出到latex，一种基于ΤΕΧ的排版系统。</li></ul><p>一般来说，我们导出成CSV文件，直接在Excel中操作，生成相应的图形就可以了。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221430719.png" alt="image-20220722143044617" style="zoom:50%;"><p>另外介绍几个可以做图的工具：</p><p><strong>JMH Visualizer</strong>这里有一个开源的项目（<a href="https://jmh.morethan.io/%EF%BC%89" target="_blank" rel="noreferrer">https://jmh.morethan.io/）</a> ，通过导出json文件，上传之后，可得到简单的统计结果。个人认为它的展示方式并不是很好。</p><p><strong>jmh-visual-chart</strong></p><p>相比较而言，下面这个工具（<a href="http://deepoove.com/jmh-visual-chart%EF%BC%89" target="_blank" rel="noreferrer">http://deepoove.com/jmh-visual-chart）</a> ，就相对直观一些。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221431598.png" alt="image-20220722143107510" style="zoom:50%;"><p><strong>meta-chart</strong></p><p>一个通用的在线图表生成器。（<a href="https://www.meta-chart.com/%EF%BC%89%EF%BC%8C%E5%AF%BC%E5%87%BACSV%E6%96%87%E4%BB%B6%E5%90%8E%EF%BC%8C%E5%81%9A%E9%80%82%E5%BD%93%E5%A4%84%E7%90%86%EF%BC%8C%E5%8D%B3%E5%8F%AF%E5%AF%BC%E5%87%BA%E7%B2%BE%E7%BE%8E%E5%9B%BE%E5%83%8F%E3%80%82" target="_blank" rel="noreferrer">https://www.meta-chart.com/），导出CSV文件后，做适当处理，即可导出精美图像。</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207221431588.png" alt="image-20220722143129518" style="zoom:50%;"><p>像Jenkins等一些持续集成工具，也提供了相应的插件，用来直接显示这些测试结果。</p><h3 id="非注解启动运行" tabindex="-1">非注解启动运行 <a class="header-anchor" href="#非注解启动运行" aria-label="Permalink to &quot;非注解启动运行&quot;">​</a></h3><p>使用注解与不使用注解其实都是一样，只不过使用注解更加方便。在运行时，注解配置被用于解析生成BenchmarkListEntry配置类实例，而在<code>代码中使用Options配置也是被解析成一个个BenchmarkListEntry配置类实例</code>（每个方法对应一个）。非注解方式我们可以使用OptionsBuilder构造一个Options，例如，非注解方式实现上面的例子。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> throws RunnerException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> options </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">LinkedListIterationBenchMark</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// .exclude(&quot;testJackson&quot;)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forks</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">threads</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">timeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NANOSECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">warmupIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">warmupTime</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeValue</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">seconds</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">))</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">measurementIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">measurementTime</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeValue</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">seconds</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">))</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">mode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AverageTime</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">options</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205101404304.png" alt="image-20220510140428259" style="zoom:80%;"><ul><li>include：<code>导入一个基准测试类。调用方法传递的是类的简单名称</code>，不含包名。</li><li>exclude：<code>排除哪些方法</code>。默认JMH会为include导入的类的每个public方法都生成一个BenchmarkListEntry配置类实例，也就是把每个public方法都当成是基准测试方法，这时我们就可以使用exclude排除不需要参与基准测试的方法。例如本例中使用exclude排除了testJackson方法。</li></ul><p>打jar包放服务器上执行 对于大型的测试，需要测试时间比较久、线程比较多的情况，我们可以将写好的基准测试项目打包成jar包丢到linux服务器上执行。对于吞吐量基准测试，建议放到服务器上执行，其结果会更准确一些，硬件、系统贴近线上环境、也不受本机开启的应用数、硬件配置等因素影响。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">java </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">jar my</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">benchmarks</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">jar</span></span></code></pre></div><p>在IDEA中执行 对于一般的方法执行耗时测试，我们不需要把测试放到服务器上执行，例如测试对比几个json解析框架的性能。在idea中，我们可以编写一个单元测试方法，在单元测试方法中创建一个org.openjdk.jmh.runner.Runner，调用Runner的run方法执行基准测试。但JMH不会去扫描包，不会执行每个基准测试方法，这需要我们通过配置项来告知JMH需要执行哪些基准测试方法。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">BenchmarkTest</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">	</span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#A6ACCD;">	</span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">test</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">throws</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RunnerException</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    	</span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> options </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null;</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 创建Options</span></span>
<span class="line"><span style="color:#A6ACCD;">   		</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">options</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">	</span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>复制代码 完整例子如下：</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">BenchmarkTest</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">test</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">throws</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RunnerException</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> options </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                 </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">JsonBenchmark</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#89DDFF;">                 </span><span style="color:#676E95;font-style:italic;">// .output(&quot;/tmp/json_benchmark.log&quot;)</span></span>
<span class="line"><span style="color:#A6ACCD;">                 </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">options</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>Options在前面已经介绍过了，由于本例中JsonBenchmark这个类已经使用了注解，因此Options只需要配置需要执行基准</p><p>测试的类。如果需要执行多个基准测试类，include方法可以多次调用。</p><p>如果需要将测试结果输出到文件，可调用output方法配置文件路径，不配置则输出到控制台。</p><h2 id="测试多个方法-重要" tabindex="-1">测试多个方法(重要) <a class="header-anchor" href="#测试多个方法-重要" aria-label="Permalink to &quot;测试多个方法(重要)&quot;">​</a></h2><p>假设我们需要在JsonBenchmark类中创建两个基准测试方法，一个是testGson，另一个是testJackson，用于对比Gson与Jackson这两个框架解析json的性能。那么<code>我们可以将除@Benchmark注解外的其它注解都声明到类上，让两个基准测试方法都使用同样的配置。</code></p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AverageTime</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定mode为Mode.AverageTime</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Fork</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定并行数量</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Threads</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定线程数量</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">OutputTimeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NANOSECONDS</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定输出的耗时时长的单位</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Warmup</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Measurement</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">State</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Scope</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Thread</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 有公共变量必须写他，不然会报错</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">LinkedListIterationBenchMark</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> SIZE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10000</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> list </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">LinkedList</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Setup</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setUp</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> SIZE</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">valueOf</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">i</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">forIndexIterate</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">();</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">i</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">print</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">forEachIterate</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> s </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> list</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">print</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">throws</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RunnerException</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">LinkedListIterationBenchMark</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">//可选，不写默认输出到控制台</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">//.output(&quot;E:/Benchmark.log&quot;)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">opt</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205101343214.png" alt="image-20220510134308157" style="zoom:80%;"><h2 id="测试单个方法" tabindex="-1">测试单个方法 <a class="header-anchor" href="#测试单个方法" aria-label="Permalink to &quot;测试单个方法&quot;">​</a></h2><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AverageTime</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定mode为Mode.AverageTime</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Fork</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定并行数量</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Threads</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定线程数量</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">OutputTimeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NANOSECONDS</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 指定输出的耗时时长的单位</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Warmup</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Measurement</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">iterations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">time</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">timeUnit</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testFor</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> sum </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1000000</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        sum </span><span style="color:#89DDFF;">+=</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">AfterEach</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">after</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws RunnerException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">JMHTest</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">warmupIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">measurementIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//可选，不写默认输出到控制台</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// .output(&quot;E:/Benchmark.log&quot;)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">opt</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>启动方法</p><p>在启动方法中，可以直接指定上述说到的一些参数，并且能将测试结果输出到指定文件中，</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 仅限于IDE中运行</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 命令行模式 则是 build 然后 java -jar 启动</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     *</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 1. 这是benchmark 启动的入口</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 2. 这里同时还完成了JMH测试的一些配置工作</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 3. 默认场景下，JMH会去找寻标注了@Benchmark的方法，</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">          可以通过include和exclude两个方法来完成包含以及排除的语义</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     */</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> throws RunnerException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 包含语义</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 可以用方法名，也可以用XXX.class.getSimpleName()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">Helloworld</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 排除语义</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">exclude</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">Pref</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 预热10轮</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">warmupIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 代表正式计量测试做10轮，</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 而每次都是先执行完预热再执行正式计量，</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 内容都是调用标注了@Benchmark的代码。</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">measurementIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">//  forks(3)指的是做3轮测试，</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 因为一次测试无法有效的代表结果，</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 所以通过3轮测试较为全面的测试，</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 而每一轮都是先预热，再正式计量。</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forks</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 不写默认输出到控制台</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">output</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">E:/Benchmark.log</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">opt</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span></code></pre></div><p>还需要使用@State注解指定字段的共享域。在本例中，我们使用@Threads注解声明创建两个线程来执行基准测试方法，假设我们配置@State(Scope.Thread)，那么在不同线程中，gsonParser、jacksonParser这两个字段都是不同的实例。</p><p>以testGson方法为例，我们可以认为JMH会为每个线程克隆出一个gsonParser对象。如果在testGson方法中打印gsonParser对象的hashCode，你会发现，相同线程打印的结果相同，不同线程打印的结果不同。例如：</p><h2 id="demo演示" tabindex="-1">DEMO演示 <a class="header-anchor" href="#demo演示" aria-label="Permalink to &quot;DEMO演示&quot;">​</a></h2><p>这里先演示一个DEMO，让不了解JMH的同学能够快速掌握这个工具的大概用法。</p><h3 id="_1-测试项目构建" tabindex="-1">1. 测试项目构建 <a class="header-anchor" href="#_1-测试项目构建" aria-label="Permalink to &quot;1. 测试项目构建&quot;">​</a></h3><p>JMH是内置Java9及之后的版本。这里是以Java8进行说明。</p><p>第二种方式就是直接在现有的maven项目中添加<code>jmh-core</code>和<code>jmh-generator-annprocess</code>的依赖来集成JMH。</p><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.openjdk.jmh</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">jmh-core</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">1.35</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.openjdk.jmh</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">jmh-generator-annprocess</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">1.35</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h3 id="_2-编写性能测试" tabindex="-1">2. 编写性能测试 <a class="header-anchor" href="#_2-编写性能测试" aria-label="Permalink to &quot;2. 编写性能测试&quot;">​</a></h3><p>这里我以测试LinkedList 通过index 方式迭代和foreach 方式迭代的性能差距为例子，编写测试类，涉及到的注解在之后会讲解，</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">State</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Scope</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Benchmark</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">OutputTimeUnit</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Threads</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Threads</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MAX</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">LinkedListIterationBenchMark</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> SIZE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10000</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> list </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">LinkedList</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Setup</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setUp</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> SIZE</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">valueOf</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">i</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">forIndexIterate</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">();</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">i</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">print</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Benchmark</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BenchmarkMode</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Mode</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Throughput</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">forEachIterate</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> s </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> list</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">print</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="_3-执行测试" tabindex="-1">3. 执行测试 <a class="header-anchor" href="#_3-执行测试" aria-label="Permalink to &quot;3. 执行测试&quot;">​</a></h3><p>运行 <strong>JMH</strong> 基准测试有两种方式，一个是生产jar文件运行，另一个是直接写main函数或者放在单元测试中执行。</p><p>我们日常中遇到的一般是一些小测试，比如我上面写的例子，直接在IDE中跑就好了。启动方式如下：</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> throws RunnerException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Options</span><span style="color:#A6ACCD;"> opt </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">OptionsBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">include</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">LinkedListIterationBenchMark</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSimpleName</span><span style="color:#89DDFF;">())</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forks</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">warmupIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">measurementIterations</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">//可选，不写默认输出到控制台</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">output</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">E:/Benchmark.log</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Runner</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">opt</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">run</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="_4-报告结果" tabindex="-1">4. 报告结果 <a class="header-anchor" href="#_4-报告结果" aria-label="Permalink to &quot;4. 报告结果&quot;">​</a></h3><p>输出结果如下，</p><p>最后的结果：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Benchmark                                      Mode  Cnt     Score   Error  Units</span></span>
<span class="line"><span style="color:#A6ACCD;">LinkedListIterationBenchMark</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">forEachIterate   thrpt    </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">1192.380</span><span style="color:#A6ACCD;">          ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">s</span></span>
<span class="line"><span style="color:#A6ACCD;">LinkedListIterationBenchMark</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">forIndexIterate  thrpt    </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">206.866</span><span style="color:#A6ACCD;">          ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">s</span></span></code></pre></div><h2 id="测试结果报告的参数解释" tabindex="-1">测试结果报告的参数解释 <a class="header-anchor" href="#测试结果报告的参数解释" aria-label="Permalink to &quot;测试结果报告的参数解释&quot;">​</a></h2><p>最后是关于如何阅读JMH的测试报告，这里的这份报告是上边讲解的代码案例中的测试结果。由于报告的内容量比较大，所以这里只挑报告的结果来进行讲解：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Benchmark                   Mode  Cnt         Score        Error   Units</span></span>
<span class="line"><span style="color:#A6ACCD;">JMHHelloWord</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">baseMethod    thrpt   </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">14343234.962</span><span style="color:#A6ACCD;"> ± </span><span style="color:#F78C6C;">585752.043</span><span style="color:#A6ACCD;">  ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ms</span></span>
<span class="line"><span style="color:#A6ACCD;">JMHHelloWord</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">measureRight  thrpt   </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">260749.234</span><span style="color:#A6ACCD;"> ±   </span><span style="color:#F78C6C;">5324.982</span><span style="color:#A6ACCD;">  ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ms</span></span>
<span class="line"><span style="color:#A6ACCD;">JMHHelloWord</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">measureWrong  thrpt   </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">524449.863</span><span style="color:#A6ACCD;"> ±   </span><span style="color:#F78C6C;">8330.106</span><span style="color:#A6ACCD;">  ops</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">ms</span></span></code></pre></div><p>从报告的左往右开始介绍起：</p><ul><li>Benchmark 就是对应的测试方法。</li><li>Mode 测试的模式。</li><li>Cnt 循环了多少次。</li><li>Score 是指测试的得分，这里因为选择了以thrpt的模式进行测试，所以分值越高表示吞吐率越高。</li><li>Error 代表并不是表示执行用例过程中出现了多少异常，而是指这个Score的精度可能存在误差，所以前边还有个± 的符号。</li></ul><p>关于Error的解释，在stackoverflow中也有解释：</p><blockquote><p><a href="https://codereview.stackexchange.com/questions/90886/jmh-benchmark-metrics-evaluation" target="_blank" rel="noreferrer">https://codereview.stackexchange.com/questions/90886/jmh-benchmark-metrics-evaluation</a></p></blockquote><h1 id="postman-接口测试" tabindex="-1">Postman 接口测试 <a class="header-anchor" href="#postman-接口测试" aria-label="Permalink to &quot;Postman 接口测试&quot;">​</a></h1><p>Postman 是一款我们在工作中使用频率非常高的 API 调试工具，估计很多童鞋在使用它时也比较粗暴，填好接口地址、参数，直接 send 就完事了。估计大家要说了，这么简单的东西还能玩出什么花来。今天就和大家安利几个非常实用、但是可能一直被忽视的功能，用完之后，简直不要太香！</p><h2 id="环境变量" tabindex="-1">环境变量 <a class="header-anchor" href="#环境变量" aria-label="Permalink to &quot;环境变量&quot;">​</a></h2><p>我们通过一个例子来看一下环境变量的用法，在一个项目的生命周期中，可能会有开发环境、测试环境、预上线环境、线上环境等众多的不同环境，这时候就可以通过环境变量来管理接口的地址以及端口。</p><p>点击左侧的<code>Environments</code>，系统中默认已经存在了一个<code>Globals</code>的全局环境，在这里可以存放一些通用的公共变量的值。先在这里写入<code>host</code>和<code>port</code>信息：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDodsJRLuibttrK5fB6XMSKfUw479Xg87jJglIggpp20ZxL4xb1gOkyx9Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在需要使用变量时，可以在访问接口时使用双大括号包裹变量，以<code></code>的方式进行引用：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDo318tNtAia9ZcnqQib54InyvJ2nNbmau6TpXfDrsge77ggUKK7YIia9iaMw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>除了默认的全局环境外，也可以自己创建新的环境来存放变量。在下面的例子中，创建了<code>local</code>和<code>test</code>两个环境，这样我们可以直接在两个环境间进行切换激活，简化了开发中测试接口的过程，不再需要频繁地改动接口的地址。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoEx2iao3B5ElM2Z5c0vrJh0YiaVy4dJSHm3KuHicuJLdSdtkB0HIicKicrpA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>如果激活的环境和全局环境中有名称重复的变量，那么当前激活的环境中的变量具有更高的优先级，它会直接覆盖<code>globals</code>环境中变量的值：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDobKWDzqgMPDkmw2SlZJx2gzhzib0ibTQBJpT6aYyB85FibJNsIO2mJcgGw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在上面，我们将环境变量分为了两类，普通环境变量和全局变量。总的来说，全局变量具有更高的使用范围，即使切换到自己创建的环境，全局变量仍然可用。但是我们自己创建的环境之间是相互隔离的，如果切换到一个环境，那么其他环境中的变量将不再可用。</p><p>像上面这样手动写入变量的值，在某些时候可能不太方便满足一些需求，因此 postman 提供了一种方法，允许使用脚本来改变环境变量的值。我们来看一下发送请求中的<code>Pre-request Script</code>和<code>Tests</code>模块，它们是在请求发送前或完成后执行的脚本，具体的使用在后面具体介绍，现在我们只需要知道能在这里执行 js 代码就可以了。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoSB7LpO5Bf4NiaLlWXibw1NN3d1C5xLoTmOavj4Omzzw6FSsHPmLzugiaw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>下面，在<code>Pre-request Script</code>中加入两行 js 代码：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">pm.globals.set(&quot;key1&quot;,&quot;value1&quot;);</span></span>
<span class="line"><span style="color:#A6ACCD;">pm.environment.set(&quot;key2&quot;,&quot;value2&quot;);</span></span></code></pre></div><p>执行完成请求后再次查看环境变量，全局环境和当前环境中都写入了新的值：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoVj7vo3FYicdiag0LcFCf7RvDdqSJFick8M1SyECxI6ttoQTqia4icxODRAA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>同样，也可以使用脚本删除变量：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">pm.globals.unset(&quot;key1&quot;);</span></span>
<span class="line"><span style="color:#A6ACCD;">pm.environment.unset(&quot;key2&quot;);</span></span></code></pre></div><p>除了上面的两类变量外，postman 中的<code>Collection</code>也可以存储变量。<code>Collection</code>可以理解为一个集合，通常在使用中我们会将一个应用系统中的接口放在一个集合中，集合中的变量拥有更小的使用范围，仅在当前集合内可用：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoiaXrOPxm1xLScqvLzamUkicuKtakBXlibGa71acA3he1470IkmP27q5MQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>同样，也可以在脚本中对它进行操作：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">pm.collectionVariables.set(&quot;key3&quot;,&quot;value3&quot;);</span></span>
<span class="line"><span style="color:#A6ACCD;">pm.collectionVariables.unset(&quot;key3&quot;);</span></span></code></pre></div><p>在有了环境变量的基础后，再回头看一下上面提到的<code>Pre-request Script</code>和<code>Tests</code>，它们是两个比较类似的功能，用处也非常广泛。</p><h2 id="pre-request-script" tabindex="-1">Pre-request Script <a class="header-anchor" href="#pre-request-script" aria-label="Permalink to &quot;Pre-request Script&quot;">​</a></h2><h3 id="运行-js-脚本" tabindex="-1">运行 JS 脚本 <a class="header-anchor" href="#运行-js-脚本" aria-label="Permalink to &quot;运行 JS 脚本&quot;">​</a></h3><p><code>Pre-request Script</code>可以翻译为预请求脚本，是在请求发送前被执行的代码逻辑，可以在这里执行一些<code>js</code>代码。通过下面的简单例子进行一下演示，先准备一个后台接口，将前端传递过来的时间戳转换为时间并打印：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">@GetMapping(&quot;test1&quot;)</span></span>
<span class="line"><span style="color:#A6ACCD;"> public void time(@RequestParam(&quot;time&quot;) String time){</span></span>
<span class="line"><span style="color:#A6ACCD;">     Date date = new Date(Long.parseLong(time));</span></span>
<span class="line"><span style="color:#A6ACCD;">     System.out.println(date);</span></span>
<span class="line"><span style="color:#A6ACCD;"> }</span></span></code></pre></div><p>在<code>Pre-request Script</code>中利用 js 代码获取当前时间，并放到集合变量中，在请求中传给后端：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoCTmuX5U6kUeISPmGiazibLlqgM5GJCmVDFGThV1zXMYxiczOwVPuuNOqA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>发送请求，控制台打印了前端接口的调用时间：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">Tue Aug 01 14:14:29 CST 2021</span></span></code></pre></div><h3 id="发送-get-请求" tabindex="-1">发送 GET 请求 <a class="header-anchor" href="#发送-get-请求" aria-label="Permalink to &quot;发送 GET 请求&quot;">​</a></h3><p><code>Pre-request Script</code>的另一大用途就是，在请求当前接口前，通过执行脚本来先请求一下其他接口。在 postman 中，已经内置了<code>sendRequest</code>方法来发送<code>get</code>方法请求。我们在这里调用一个本地接口，并将信息打印到<code>console</code>控制台（可以通过 <code>Show Postman Console</code>开启）。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoPPlnfEJVfIyncLq416jWNQxW31ZbwNelrHgzekXLzbOZFVvR8AibqVQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>通过控制台的打印顺序，也可以看到，是先执行了<code>Pre-request</code>中的请求后，才去执行真正目标接口的请求。直接像上面这样调用<code>sendRequest</code>时，默认发送的<code>get</code>请求，如果需要使用<code>post</code>请求、配置请求<code>header</code>或使用<code>json</code>传参的话，可以使用下面单独封装请求的方式。</p><h3 id="发送-post-请求" tabindex="-1">发送 POST 请求 <a class="header-anchor" href="#发送-post-请求" aria-label="Permalink to &quot;发送 POST 请求&quot;">​</a></h3><p>在这里，我们通过一个例子来演示<code>Pre-request Script</code>在具体的工作中能够怎样应用。有一个很普遍的场景，通常在调试需要权限认证的接口时，需要提前通过一个接口获取 token，然后再访问目标接口时携带这个 token。</p><p>这时就可以在<code>Pre-request Script</code>中先调用获取 token 的接口，再将 token 设置到集合的环境变量中，在之后的接口调用中引用它。在这里先准备了一个应用了<code>Shiro+JWT</code>的项目，其中通过登录接口获取 token，之后的其他接口都需要带上这个 token 用于认证 。</p><p>我们在<code>sendRequest</code>发送<code>get</code>请求的基础上，进行一些修改。首先定义一个变量，在其中使用<code>url</code>指定请求地址，<code>method</code>指定请求方法，<code>body</code>携带参数，最后使用<code>sendRequest</code>进行请求的发送。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoTXTCct1PunhU6UnNhX7Tib9ibveTeo2n7PELXoaGmadl4mEUr2uGhvow/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在获取完成 token 后，通过下面的代码将获取的 token 放入了<code>Collection</code>的变量中：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">pm.collectionVariables.set(&quot;TOKEN&quot;,response.json().data.token);</span></span></code></pre></div><p>查看<code>Collection</code>中的变量，已经保存了刚才获取的 token：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoexhRpgNGBpFZeQOow3bpYBDuGcG95QafSQ6QcDqBq0xtrH0ayxayug/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在需要认证的接口<code>header</code>中，引用这个 token，就可以正常地调用接口了：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoXshQwMc6IXgGKOhMZKtDialHgQs2qXM0FWucohbhppsRjTb7rsnG7RQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在上面的例子中，我们使用的是<code>urlencoded</code>的表单传参方式，如果接口定义是使用 json 方式传参，可以写成下面的格式：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">body: {</span></span>
<span class="line"><span style="color:#A6ACCD;">  mode: &#39;raw&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">  raw: JSON.stringify({ key: &#39;value&#39; })</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><p>如果需要传递<code>header</code>请求头信息，也可以在自定义的请求中添加：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">const loginRequest = {</span></span>
<span class="line"><span style="color:#A6ACCD;">  url: &#39;...&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">  header: [</span></span>
<span class="line"><span style="color:#A6ACCD;">      &#39;Key1 : Value1&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">      &#39;Key2 : Value2&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">  ],</span></span>
<span class="line"><span style="color:#A6ACCD;">  ...</span></span>
<span class="line"><span style="color:#A6ACCD;">};</span></span></code></pre></div><p>具体的使用中需要添加什么字段非常的灵活，可以由我们自行进行配置。</p><h2 id="tests" tabindex="-1">Tests <a class="header-anchor" href="#tests" aria-label="Permalink to &quot;Tests&quot;">​</a></h2><p>和<code>Pre-request Script</code>相对，<code>Tests</code>是在请求完成后执行的操作。这里我们回顾一下上面<code>Pre-request Script</code>中发送<code>post</code>请求的例子，其实可以通过<code>Tests</code>来进行改进。</p><p>因为在上面的例子中，获取到的 token 是<code>JWT</code>生成的，具有一定有效时间，在一段时间内是都可以复用的。因此我们可以先手动调用一次<code>login</code>接口获取 token，完成后在<code>Tests</code>中使用脚本将获取的 token 放入<code>Collection</code>的变量中，就不需要在每次调用接口前都调用<code>login</code>接口重复获取 token 了。</p><p>调用<code>login</code>接口并存入缓存的过程：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDovdAGuyMXdaqxK4JgSEz86S5OSI5ic231mZeaNicjfH8daREoVvSicASaA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>之后在调用其他需要携带这个 token 的接口时，使用<code></code>的方式，就会自动填充刚才保存的<code>TOKEN</code>值。这样在获取到新的 token 后，每个接口中的 token 都会自动更新，就不需要再手动复制到每个接口了，极大地减少了工作量。</p><p>在 postman 中，在<code>Collection</code>中可以创建<code>Folder</code>文件夹，并且集合和文件夹上也可以添加<code>Pre-request Script</code>和<code>Tests</code>脚本。我们来看一下位于<code>Folder</code>中的请求，在执行<code>Pre-request Script</code>和<code>Tests</code>时顺序是怎样的，在每个环节中加入对应的打印语句，最后输出的结果是这样的：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/zpom4BeZSicZPYw9B7oJxw4W1eNUXuWDoHqWmkM8wACqLhrypMkcicCu85o12JZ4Jzo6eZFfVaS6VOoibRW7qvCPg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>也就是说，在发送请求前，postman 会先执行所有<code>Pre-request Script</code>，并且顺序是集合最先、文件夹次之、最后是请求中的，在执行完成真正的请求后执行所有的<code>Tests</code>，顺序同上。这也就要求我们在使用<code>Pre-request Script</code>及<code>Tests</code>功能前，首先要求我们对接口的调用顺序、数据的流向有一个明确的了解，这样才能保证不会出现取不到值或更新错误的情况。</p><h1 id="faker-生产假数据" tabindex="-1">Faker(生产假数据) <a class="header-anchor" href="#faker-生产假数据" aria-label="Permalink to &quot;Faker(生产假数据)&quot;">​</a></h1><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251819019.png" alt="image-20220425181917914" style="zoom:50%;"><h2 id="faker-是干什么的" tabindex="-1">Faker 是干什么的？ <a class="header-anchor" href="#faker-是干什么的" aria-label="Permalink to &quot;Faker 是干什么的？&quot;">​</a></h2><p>Faker 是专门用来产生各种假数据的辅助工具库。</p><p>比如，你想产生个和真实数据一样的有姓名、有地址的用户。</p><p>代码库地址：<a href="https://github.com/DiUS/java-faker" target="_blank" rel="noreferrer">https://github.com/DiUS/java-faker</a></p><h2 id="为什么在项目里用它" tabindex="-1">为什么在项目里用它？ <a class="header-anchor" href="#为什么在项目里用它" aria-label="Permalink to &quot;为什么在项目里用它？&quot;">​</a></h2><p>我们经常需要造数据去测试，但是，如果没有工具辅助，我们自己造数据，存在一些问题。</p><h3 id="数据是需要格式的" tabindex="-1">数据是需要格式的 <a class="header-anchor" href="#数据是需要格式的" aria-label="Permalink to &quot;数据是需要格式的&quot;">​</a></h3><p>很多关于项目，都需要一些格式上尽量能模仿真实世界的数据。</p><p>比如，国内用户的姓名，大部分都是两字、三字的姓名，叫王大，就不能叫 王da 这种。</p><p>又比如，国内的地址是 xx市xx区xx街道xx号 这种的，就不能胡写一个几个没意义的汉字来当地址。</p><p>用贴近真实格式的数据，<code>一来可以测出我们对用户的数据解析是否存在问题，二来可以测出数据库内的字段长度是否没问题</code>。所以，格式对产生出可靠地测试结果，是很重要的。</p><h3 id="数据的量大" tabindex="-1">数据的量大 <a class="header-anchor" href="#数据的量大" aria-label="Permalink to &quot;数据的量大&quot;">​</a></h3><p>有的测试数据量都是上十万、百万的，这些量级的数据并不是只会产生一次。</p><p>甚至几乎每个项目，每个项目的每次测试，可能都会需要新的数据，需要能源源不断地产生出来。</p><p>更甚至的是，有时候还想要根据我们的要求，在恰当的时候，产生某种关系的数据，或者以某些特定频率产生。比如，两秒后产生一次数据；比如，产生一批姓王的数据。</p><p>以上这三种要求综合起来，要是我们自己造数据，那真是要了命了。</p><p>与其自己开发，不如用现成的——Faker 库被我们找到了。</p><p><code>Faker库可以创造三百多种数据，而且还很容易对它进行扩展改造，去产生更多的贴合我们需求的数据。</code></p><h2 id="使用示例" tabindex="-1">使用示例 <a class="header-anchor" href="#使用示例" aria-label="Permalink to &quot;使用示例&quot;">​</a></h2><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">com.github.javafaker</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">javafaker</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">1.0.2</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t2</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Faker</span><span style="color:#A6ACCD;"> faker </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Faker</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Locale</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">CHINA</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">name</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">fullName</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> firstName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">name</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">firstName</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> lastName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">name</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">lastName</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> streetAddress </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">address</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">streetAddress</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">name</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">firstName</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">lastName</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">streetAddress</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251820149.png" alt="image-20220425182054048" style="zoom:67%;"><p>几行代码，我们需要的一个用户就有了。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t3</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Faker</span><span style="color:#A6ACCD;"> faker </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Faker</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Locale</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">CHINA</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">5</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">print</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">name</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">fullName</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">print</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">country</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">capital</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">address</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">streetAddress</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">address</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">streetAddress</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">faker</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">weather</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">temperatureCelsius</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205101944499.png" alt="image-20220510194445444" style="zoom:80%;"><p>用上 Faker 后，小伙伴们纷纷表示“有更多的时间摸鱼了”。</p><h2 id="具体用例" tabindex="-1">具体用例 <a class="header-anchor" href="#具体用例" aria-label="Permalink to &quot;具体用例&quot;">​</a></h2><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Faker</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">FakeValuesService</span><span style="color:#A6ACCD;"> fakeValuesService</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RandomService</span><span style="color:#A6ACCD;"> random</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">randomService </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> random</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">fakeValuesService </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> fakeValuesService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">ancient </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Ancient</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">app </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">App</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">artist </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Artist</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">avatar </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Avatar</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">aviation </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Aviation</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">lorem </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Lorem</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">music </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Music</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Name</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">number </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Number</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">internet </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Internet</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">phoneNumber </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">PhoneNumber</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">pokemon </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Pokemon</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">address </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Address</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">book </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Book</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">business </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Business</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">chuckNorris </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ChuckNorris</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">color </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Color</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">idNumber </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">IdNumber</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">hacker </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Hacker</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">company </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Company</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">crypto </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Crypto</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">elderScrolls </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ElderScrolls</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">commerce </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Commerce</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">currency </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Currency</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">options </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Options</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">code </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Code</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">file </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">File</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">finance </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Finance</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">food </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Food</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">gameOfThrones </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">GameOfThrones</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">dateAndTime </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">DateAndTime</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">demographic </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Demographic</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">dog </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Dog</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">educator </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Educator</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">shakespeare </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Shakespeare</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">slackEmoji </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">SlackEmoji</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">space </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Space</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">superhero </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Superhero</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">team </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Team</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">bool </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Bool</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">beer </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Beer</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">university </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">University</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">cat </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Cat</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">stock </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Stock</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">lordOfTheRings </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">LordOfTheRings</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">zelda </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Zelda</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">harryPotter </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HarryPotter</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">rockBand </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">RockBand</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">esports </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Esports</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">friends </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Friends</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">hipster </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Hipster</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">job </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Job</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">twinPeaks </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">TwinPeaks</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">rickAndMorty </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">RickAndMorty</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">yoda </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Yoda</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">matz </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Matz</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">witcher </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Witcher</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">dragonBall </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">DragonBall</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">funnyName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">FunnyName</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">hitchhikersGuideToTheGalaxy </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HitchhikersGuideToTheGalaxy</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">hobbit </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Hobbit</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">howIMetYourMother </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HowIMetYourMother</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">leagueOfLegends </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">LeagueOfLegends</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">overwatch </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Overwatch</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">robin </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Robin</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">starTrek </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StarTrek</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">weather </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Weather</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">lebowski </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Lebowski</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">medical </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Medical</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">country </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Country</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">animal </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Animal</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">backToTheFuture </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">BackToTheFuture</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">princessBride </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">PrincessBride</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">buffy </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Buffy</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">relationships </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Relationships</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">nation </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Nation</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">dune </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Dune</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">aquaTeenHungerForce </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">AquaTeenHungerForce</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">programmingLanguage </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ProgrammingLanguage</span><span style="color:#89DDFF;">(this);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h1 id="wiremock" tabindex="-1">Wiremock <a class="header-anchor" href="#wiremock" aria-label="Permalink to &quot;Wiremock&quot;">​</a></h1><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251821196.png" alt="image-20220425182131067" style="zoom:67%;"><h2 id="wiremock-是干什么的" tabindex="-1">Wiremock 是干什么的？ <a class="header-anchor" href="#wiremock-是干什么的" aria-label="Permalink to &quot;Wiremock 是干什么的？&quot;">​</a></h2><p>Wiremock 是一个可以模拟服务的测试框架`</p><p>比如，你想测试访问阿里的支付相关接口的代码逻辑，就可以用它来做测试。</p><p><strong>代码库地址</strong>：<a href="https://github.com/wiremock/wiremock" target="_blank" rel="noreferrer">https://github.com/wiremock/wiremock</a></p><h2 id="为什么在项目里用它-1" tabindex="-1">为什么在项目里用它？ <a class="header-anchor" href="#为什么在项目里用它-1" aria-label="Permalink to &quot;为什么在项目里用它？&quot;">​</a></h2><p>比如，我们需要调用银行接口去做资金业务，调用微信接口去做微信登录……这些调用第三方服务的测试存在一个问题：即太过依赖对方的平台。假如对方平台限制了一些 IP，或者限制了访问频率，又或者就是服务出现了维护，都会影响我们自身的功能测试。</p><p>为了解决上述问题，在之前，我们需要自己写代码模仿第三方的接口，等我们自己全部测试没问题了，再去和第三方联调。对于这种模拟出来的接口，我们称作挡板。</p><p>可是，这种方式是个苦活，没人愿意干。因为每接入一个第三方，可能都需要做挡板。辛苦做个挡板，就是单纯为了测试。如果第三方的接口做了改造，你这边还得跟着改。</p><p>大家可以想想，换成你自己，你愿意做这么件事儿吗？</p><p>这时候，Wiremock 的价值就体现出来了。有了 Wiremock，挡板这种东西就再也不存在了，<code>直接在单元测试里模拟测试即可</code>，像这样：</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">WireMock</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">stubFor</span><span style="color:#89DDFF;">(</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#82AAFF;">urlPathMatching</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/aliyun/.*</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">))</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">willReturn</span><span style="color:#89DDFF;">(</span><span style="color:#82AAFF;">aResponse</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                        </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">withStatus</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">200</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                        </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">withHeader</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">Content-Type</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> APPLICATION_JSON</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                        </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">withBody</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#C3E88D;">testing-library</span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#C3E88D;">: </span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#C3E88D;">WireMock</span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">CloseableHttpClient</span><span style="color:#A6ACCD;"> httpClient </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> HttpClients</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">createDefault</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#C792EA;">HttpGet</span><span style="color:#A6ACCD;"> request </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HttpGet</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">format</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">:%s/aliyun/wiremock</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> port</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#C792EA;">HttpResponse</span><span style="color:#A6ACCD;"> httpResponse </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> httpClient</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">execute</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">request</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> stringResponse </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">convertHttpResponseToString</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">httpResponse</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#82AAFF;">verify</span><span style="color:#89DDFF;">(</span><span style="color:#82AAFF;">getRequestedFor</span><span style="color:#89DDFF;">(</span><span style="color:#82AAFF;">urlEqualTo</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ALIYUN_WIREMOCK_PATH</span><span style="color:#89DDFF;">)));</span></span>
<span class="line"><span style="color:#82AAFF;">assertEquals</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">200</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> httpResponse</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getStatusLine</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">getStatusCode</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#82AAFF;">assertEquals</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">APPLICATION_JSON</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> httpResponse</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getFirstHeader</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">Content-Type</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">getValue</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#82AAFF;">assertEquals</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#C3E88D;">testing-library</span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#C3E88D;">: </span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#C3E88D;">WireMock</span><span style="color:#A6ACCD;">\&quot;</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> stringResponse</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h1 id="retrofit" tabindex="-1">Retrofit <a class="header-anchor" href="#retrofit" aria-label="Permalink to &quot;Retrofit&quot;">​</a></h1><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251818583.png" alt="image-20220425181853489" style="zoom:67%;"><p><strong>Retrofit 是干什么的？</strong></p><p>Retrofit 就是一套 Http 客户端，可以用来访问第三方的 Http 服务。</p><p>比如，咱们代码里想调用一个 Http 协议的 URL，就可以用它来访问这个 URL，获取响应结果。</p><p><strong>为什么在项目里用它？</strong></p><p>在公司里，我们有些项目有如下的特点：</p><ol><li>不是基于 Spring 的项目</li><li>需要经常访问大量的第三方 Http 服务</li><li>访问 Http 服务的模型通常是异步回调</li></ol><p>以前的时候，我们访问 Http 服务，都是直接用的 HttpClient。</p><p>可是吧，HttpClient 用起来实在够麻烦的。主要也存在两个问题：</p><p>1.请求参数和 URL 拼接实在繁琐</p><p>请求参数和 URL 拼接实在是太烦人了。你想想，每调用一个接口，就需要自己去拼接参数，有的 URL，甚至十几二十个参数需要拼接。</p><p>拼接这事儿简单、枯燥、重复，还没有技术含量，但是工作量却不小，时间真的算浪费了。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">URIBuilder</span><span style="color:#A6ACCD;"> uriBuilder </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">URIBuilder</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">uriBase</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valuea</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valueb</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">c</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valuec</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">d</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valued</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">e</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valuee</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">f</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valuef</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">g</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valueg</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">h</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valueh</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">uriBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setParameter</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">i</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">valuei</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">...</span></span></code></pre></div><p>2.异步回调需要自己搞</p><p>异步回调这种模型不好处理，主要就是需要自己去搞线程池，还要对线程池管理，还要考虑出错的重试之类的容错问题，实在麻烦。</p><p>所以，我们就需要一套能用法简单，不用我们一直搞拼接参数，自己搞线程管理就能完成对第三方 Http 服务访问的库。</p><p>其实我们也想过用 Feign 这套框架的。但是，这套东西和 Spring 绑定的太紧了。如果离开 Spring，它的一些功能就没法简单的通过注解直接使用，必须自己写代码调用。</p><p>而且，Feign 要实现异步回调方式使用，尤其在协程方面，还是需要自己开发。</p><p>这时候，Retrofit 就跳进了我们的选型里。</p><p>Retrofit 的模型里，异步回调模型它支持的很好，我们只需要实现一个 Callable 就够了。</p><p>并且最清爽的是，它和 Spring 没什么关系。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">Retrofit</span><span style="color:#A6ACCD;"> retrofit </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> Retrofit</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">Builder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">baseUrl</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">http://xxx.example.com/</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">interface</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">BlogService</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GET</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">blog/{id}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Call</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ResponseBody</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getBlog</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">Path</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">id</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">BlogService</span><span style="color:#A6ACCD;"> service </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> retrofit</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">create</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">BlogService</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">Call</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ResponseBody</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> call </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> service</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getBlog</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">// 用法和OkHttp的call如出一辙,</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">// 回调</span></span>
<span class="line"><span style="color:#A6ACCD;">call</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">enqueue</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Callback</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ResponseBody</span><span style="color:#89DDFF;">&gt;()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">onResponse</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Call</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ResponseBody</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">call</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Response</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ResponseBody</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">response</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">try</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">response</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">body</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">string</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">catch</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">IOException</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            e</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">printStackTrace</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">onFailure</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Call</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ResponseBody</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">call</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Throwable</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">t</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        t</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">printStackTrace</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">});</span></span></code></pre></div><p>你看，只需要写上这些代码，我们就不需要操心恼人的 Url 拼接和异步回调的管理问题了。全交给了 Retrofit，着实推荐。</p><p><strong>代码库地址</strong>：<a href="https://github.com/square/retrofit" target="_blank" rel="noreferrer">https://github.com/square/retrofit</a></p><h1 id="前端性能测试工具-⭐" tabindex="-1">前端性能测试工具 ⭐ <a class="header-anchor" href="#前端性能测试工具-⭐" aria-label="Permalink to &quot;前端性能测试工具 ⭐&quot;">​</a></h1><h2 id="_1-google-pagespeed-insights⭐" tabindex="-1">1. Google PageSpeed Insights⭐ <a class="header-anchor" href="#_1-google-pagespeed-insights⭐" aria-label="Permalink to &quot;1. Google PageSpeed Insights⭐&quot;">​</a></h2><blockquote><p>Google PageSpeed Insights可以为网站生成性能报告，它在移动设备和桌面设备上都是免费的。并且还给出了影响页面加载速度的原因，并为这些问题提供了解决方案。网站速度按照 100 分进行划分，其中：</p></blockquote><ul><li>大于90：较好；</li><li>50-90：需要改进；</li><li>小于50：较差</li></ul><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUhVwlGicELcp7OYm0eqTxZBF9jD1P7AlwOYCDaZn38rApqgvWibFic3nHQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://pagespeed.web.dev/" target="_blank" rel="noreferrer">https://pagespeed.web.dev/</a></p><h2 id="_2-pingdom-website-speed-test" tabindex="-1">2. Pingdom Website Speed Test <a class="header-anchor" href="#_2-pingdom-website-speed-test" aria-label="Permalink to &quot;2. Pingdom Website Speed Test&quot;">​</a></h2><p>Pingdom Website Speed Test 可以全面分析影响页面Web速度的因素。此外，还可以查看网站在亚洲、欧洲等多个不同的地理位置的性能信息。</p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUhcrtmQSrTwgNeIzd0UsUicJ4xyia8hyCYia6fureNoAia8a4qpVBHjxQ3w/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://tools.pingdom.com/" target="_blank" rel="noreferrer">https://tools.pingdom.com/</a></p><h2 id="_3-webpagetest" tabindex="-1">3. WebPagetest <a class="header-anchor" href="#_3-webpagetest" aria-label="Permalink to &quot;3. WebPagetest&quot;">​</a></h2><blockquote><p>WebPagetest是 AOL 开发的一款在线的免费性能评测网站，从全球多个地点运行免费网站速度测试。可以运行简单的测试或执行高级测试，包括多步骤事务、视频捕获、内容阻塞等等。还将依据测试结果提供丰富的诊断信息，包括资源加载瀑布图，页面速度优化检查和改进建议，会给每一项内容一个最终的评级。</p></blockquote><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUyzInKsGnPfneaW566txx2uFKNXYGjia8kDmWq962Gu5dAm5mM5vBbgw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUhrSbuuLGyZ4lhFgnutCNIicibQGbj4lAg18R3FB0wticcIMor94JzKwEQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://www.webpagetest.org/" target="_blank" rel="noreferrer">https://www.webpagetest.org/</a></p><h2 id="_4-gtmetrix" tabindex="-1">4. GTmetrix <a class="header-anchor" href="#_4-gtmetrix" aria-label="Permalink to &quot;4. GTmetrix&quot;">​</a></h2><blockquote><p>GTmetrix 是一个类似于 pingdom 的工具，可以快速轻松地测试网站速度。它主要有PageSpeed和YSlow两部分组成，并提供相应的得分数据，能够真实的反应出网站的性能，并且会提供可行性建议来帮助改善网站性能。</p></blockquote><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzU3UQCo5IzLwSGwruwIPvicedFaCkkelYWExp87cWSvLO7icvrlsdTDFeg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUAmBlibxQY3nFIf2ANxFFyK2oHIjfySibesxibroPy0fgmvPAiaGDmJZmng/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://gtmetrix.com/" target="_blank" rel="noreferrer">https://gtmetrix.com/</a></p><h2 id="_5-keycdn-tool" tabindex="-1">5. Keycdn Tool <a class="header-anchor" href="#_5-keycdn-tool" aria-label="Permalink to &quot;5. Keycdn Tool&quot;">​</a></h2><blockquote><p>Keycdn Tool 是一个在全球 10 个不同地点的网站速度测试工具。它允许测试任何页面的性能。返回的结果将提供请求、内容大小和加载时间等详细信息。此外，还有一个完整的瀑布图，详细说明每个资源的加载时间和 HTTP 头</p></blockquote><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUNuPxibPZicdxRuU54ibXsBWfEMrc2o1BjeFuMcbKMXhCd5mT2lE9LxbibA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUEX7oBq2wQeQsmosiaZSn2zR7qFuS3AeaOOUgRPZicSwgicABveCeneK0w/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://tools.keycdn.com/speed" target="_blank" rel="noreferrer">https://tools.keycdn.com/speed</a></p><h2 id="_6-giftofspeed" tabindex="-1">6. GiftOfSpeed <a class="header-anchor" href="#_6-giftofspeed" aria-label="Permalink to &quot;6. GiftOfSpeed&quot;">​</a></h2><blockquote><p>GiftofSpeed是一款免费网站载入速度测试工具，可以在上面获得网站综合性能信息，它能够展示网站加载时间以及评估网站有哪些需要改进的地方，并给予一个客观的综合评分。</p></blockquote><blockquote><p>GiftofSpeed 的测试结果以瀑布流展示，可以很容易看到网站加载速度，每一项资源的的载入顺序、大小与响应时间的长短，方便了解网站的各项载入资源。此外，它还提供了载入时间最长的內部文件以及外部文件，从而分析出是由哪些因素影响了你网站的载入速度，就可以专门针对这些载入时间较长的元素进行优化，从而最大限度提升网站载入速度。</p></blockquote><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUibqrIMPWPVAYUr2npR5DEu1G0sIPV7tPw7FxwLIgCyphskpicZtnA4kw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUaria5ib5Ym69ibfyicRKFBBhfmTCKxszWSKRJreDK0Tib5mGaASjKLQ74ww/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://www.giftofspeed.com/" target="_blank" rel="noreferrer">https://www.giftofspeed.com/</a></p><h2 id="_7-pagelocity" tabindex="-1">7. Pagelocity <a class="header-anchor" href="#_7-pagelocity" aria-label="Permalink to &quot;7. Pagelocity&quot;">​</a></h2><blockquote><p>Pagelocity 是一个网站分析性能测试工具。这个工具也提供了追踪竞争对手的能力。代码检视图在类似工具中是独一无二的。如果想知道 TTFB 和图形化 DOM 元素等，都能通过这项工具获取到。</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUzMvdCxAcKibR3kRNNuh90z6zrJxicZQhbiagsDvOYfpkXBJuicnX1wNT9Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUYCmhF2oubnTUibZr63vxhf5PUqTFARuicopsJ01z4x9vRnr51HeVnAXw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"></p><p>在线地址：<a href="https://pagelocity.com/" target="_blank" rel="noreferrer">https://pagelocity.com/</a></p><h2 id="_8-sucuri-loadtime-tester" tabindex="-1">8. Sucuri Loadtime Tester <a class="header-anchor" href="#_8-sucuri-loadtime-tester" aria-label="Permalink to &quot;8. Sucuri Loadtime Tester&quot;">​</a></h2><blockquote><p>Sucuri Load Time Tester 是一个网站分析性能测试工具，它用不同的颜色表示网速快慢，可以很直观地看出测试网站在不同国家的运行速度。绿色表示畅通，没有颜色的普通数字表示一般，黄色表示中等偏慢，红色表示缓慢。</p></blockquote><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUedzXMxOMTwggkyLRsziaeDfzxThcMEeDaRXaP9rEs91hWgO7MtasU5A/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://performance.sucuri.net/" target="_blank" rel="noreferrer">https://performance.sucuri.net/</a></p><h2 id="_9-geekflare" tabindex="-1">9. GEEKFLARE <a class="header-anchor" href="#_9-geekflare" aria-label="Permalink to &quot;9. GEEKFLARE&quot;">​</a></h2><blockquote><p>GEEKFLARE 是一套免费的性能测试工具，用于测试网站的 DNS、安全性、性能、网络和 SEO 等问题。</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzU3zmTZPcAxgy9fwuAwRkI47HEZhU5hq1M6tibdOJY5nwkuJyNHHP0ojg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUPBeBy24nqf529z1GibV2KcOZooO0JVAvR9BGWFicZZhWbCBFqlST1mVw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在线地址：<a href="https://gf.dev/" target="_blank" rel="noreferrer">https://gf.dev/</a></p><h2 id="_10-dotcom-monitor" tabindex="-1">10. Dotcom-monitor <a class="header-anchor" href="#_10-dotcom-monitor" aria-label="Permalink to &quot;10. Dotcom-monitor&quot;">​</a></h2><blockquote><p>Dotcom-monitor 是一款网站性能测试工具，它可以选择测试的地点、设备的类型、屏幕分辨率、网络情况等来测试不同情况下的网站速度。</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUCziaiaY9wiaOJiaHn1qfnpPAcD4WmzfxLERicvo8iaPhdAle6iaalHeDF3MyA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在线地址：<a href="https://www.dotcom-tools.com/website-speed-test" target="_blank" rel="noreferrer">https://www.dotcom-tools.com/website-speed-test</a></p><h2 id="_11-dareboost" tabindex="-1">11. Dareboost <a class="header-anchor" href="#_11-dareboost" aria-label="Permalink to &quot;11. Dareboost&quot;">​</a></h2><blockquote><p>DareBoost 是一个免费网站速度测试和网站分析工具。它提供超过 100 种不同的检查项目用以分析你的网站速度。可以测试桌面端与行动页面、Firefox 与 Chrome 和五个节点的速度差异。</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUICckBXQIpfoIBqwbUQ31ZHVNH23ZX5m1FaGTZ3DIYiapVxYuddnMxcw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><img src="https://mmbiz.qpic.cn/mmbiz_png/EO58xpw5UMMov8eDZGgIOdg1iaEo35HzUTOxDFNBlDFokiaiaSQoTQe7nQKhJBErUibRfmdHy4bN3KqG9AvqcgGOKQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" style="zoom:67%;"><p>在线地址：<a href="https://www.dareboost.com/en" target="_blank" rel="noreferrer">https://www.dareboost.com/en</a></p><blockquote><p>Jmeter</p></blockquote><h1 id="性能测试概述" tabindex="-1">性能测试概述 <a class="header-anchor" href="#性能测试概述" aria-label="Permalink to &quot;性能测试概述&quot;">​</a></h1><h2 id="性能测试概念" tabindex="-1">性能测试概念 <a class="header-anchor" href="#性能测试概念" aria-label="Permalink to &quot;性能测试概念&quot;">​</a></h2><h3 id="为什么要用性能测试" tabindex="-1">为什么要用性能测试 <a class="header-anchor" href="#为什么要用性能测试" aria-label="Permalink to &quot;为什么要用性能测试&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221011685.png" alt="image-20230122101156548" style="zoom:67%;"><h3 id="什么是性能-性能测试" tabindex="-1">什么是性能 &amp; 性能测试 <a class="header-anchor" href="#什么是性能-性能测试" aria-label="Permalink to &quot;什么是性能 &amp; 性能测试&quot;">​</a></h3><blockquote><p>时间：系统处理用户请求的响应时间</p><p>资源：系统运行过程中，系统资源的消耗情况</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221016337.png" alt="image-20230122101629262" style="zoom:67%;"><h3 id="性能测试目的" tabindex="-1">性能测试目的 <a class="header-anchor" href="#性能测试目的" aria-label="Permalink to &quot;性能测试目的&quot;">​</a></h3><h4 id="_1-评估当前系统能力" tabindex="-1">1 评估当前系统能力 <a class="header-anchor" href="#_1-评估当前系统能力" aria-label="Permalink to &quot;1 评估当前系统能力&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221019770.png" alt="image-20230122101937721" style="zoom:67%;"><h4 id="_2-获取关键性指标进行比较" tabindex="-1">2 获取关键性指标进行比较 <a class="header-anchor" href="#_2-获取关键性指标进行比较" aria-label="Permalink to &quot;2 获取关键性指标进行比较&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221020792.png" alt="image-20230122102009595" style="zoom:67%;"><h4 id="_3-寻找性能瓶颈-优化性能" tabindex="-1">3 寻找性能瓶颈，优化性能 <a class="header-anchor" href="#_3-寻找性能瓶颈-优化性能" aria-label="Permalink to &quot;3 寻找性能瓶颈，优化性能&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221021889.png" alt="image-20230122102145838" style="zoom:67%;"><h4 id="_4-评估软件是否满足未来需要" tabindex="-1">4 评估软件是否满足未来需要 <a class="header-anchor" href="#_4-评估软件是否满足未来需要" aria-label="Permalink to &quot;4 评估软件是否满足未来需要&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221022254.png" alt="image-20230122102201198" style="zoom:67%;"><h2 id="功能测试-性能测试" tabindex="-1">功能测试 &amp; 性能测试 <a class="header-anchor" href="#功能测试-性能测试" aria-label="Permalink to &quot;功能测试 &amp; 性能测试&quot;">​</a></h2><blockquote><p>先做功能测试，再做性能测试</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221026277.png" alt="image-20230122102608193" style="zoom:67%;"><h2 id="性能测试策略" tabindex="-1">性能测试策略 <a class="header-anchor" href="#性能测试策略" aria-label="Permalink to &quot;性能测试策略&quot;">​</a></h2><h3 id="基准测试" tabindex="-1">基准测试 <a class="header-anchor" href="#基准测试" aria-label="Permalink to &quot;基准测试&quot;">​</a></h3><blockquote><p>用途：基准测试不会单独存在，为多用户并发测试和综合场景测试提供参考依据</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221033996.png" alt="image-20230122103304918" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221034089.png" alt="image-20230122103453996" style="zoom:67%;"><h3 id="负载测试" tabindex="-1">负载测试 <a class="header-anchor" href="#负载测试" aria-label="Permalink to &quot;负载测试&quot;">​</a></h3><h4 id="什么是负载测试" tabindex="-1">什么是负载测试 <a class="header-anchor" href="#什么是负载测试" aria-label="Permalink to &quot;什么是负载测试&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221039983.png" alt="image-20230122103923925" style="zoom:67%;"><h4 id="电梯案例" tabindex="-1">电梯案例 <a class="header-anchor" href="#电梯案例" aria-label="Permalink to &quot;电梯案例&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221042921.png" alt="image-20230122104230858" style="zoom:67%;"><h3 id="稳定性测试" tabindex="-1">稳定性测试 <a class="header-anchor" href="#稳定性测试" aria-label="Permalink to &quot;稳定性测试&quot;">​</a></h3><h4 id="为什么要进行稳定测试" tabindex="-1">为什么要进行稳定测试 <a class="header-anchor" href="#为什么要进行稳定测试" aria-label="Permalink to &quot;为什么要进行稳定测试&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221046269.png" alt="image-20230122104609163" style="zoom:67%;"><h4 id="稳定测试概念" tabindex="-1">稳定测试概念 <a class="header-anchor" href="#稳定测试概念" aria-label="Permalink to &quot;稳定测试概念&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221049868.png" alt="image-20230122104925809" style="zoom:67%;"><h3 id="并发测试" tabindex="-1">并发测试 <a class="header-anchor" href="#并发测试" aria-label="Permalink to &quot;并发测试&quot;">​</a></h3><h4 id="为什么进行并发测试" tabindex="-1">为什么进行并发测试 <a class="header-anchor" href="#为什么进行并发测试" aria-label="Permalink to &quot;为什么进行并发测试&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221106195.png" alt="image-20230122110603137" style="zoom:67%;"><h4 id="并发测试概念" tabindex="-1">并发测试概念 <a class="header-anchor" href="#并发测试概念" aria-label="Permalink to &quot;并发测试概念&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221132516.png" alt="image-20230122113254463" style="zoom:67%;"><h3 id="压力测试" tabindex="-1">压力测试 <a class="header-anchor" href="#压力测试" aria-label="Permalink to &quot;压力测试&quot;">​</a></h3><h4 id="为什么要压力测试" tabindex="-1">为什么要压力测试 <a class="header-anchor" href="#为什么要压力测试" aria-label="Permalink to &quot;为什么要压力测试&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221101020.png" alt="image-20230122110101890" style="zoom:67%;"><h4 id="压力测试概念" tabindex="-1">压力测试概念 <a class="header-anchor" href="#压力测试概念" aria-label="Permalink to &quot;压力测试概念&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221103972.png" alt="image-20230122110304919" style="zoom:67%;"><h2 id="性能测试指标" tabindex="-1">性能测试指标 <a class="header-anchor" href="#性能测试指标" aria-label="Permalink to &quot;性能测试指标&quot;">​</a></h2><h3 id="响应时间" tabindex="-1">响应时间 <a class="header-anchor" href="#响应时间" aria-label="Permalink to &quot;响应时间&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221342977.png" alt="image-20230122134203922" style="zoom:67%;"><blockquote><p>通过HTTP接口请求消息来测试</p><p>不包括 <strong>发消息时前端页面的处理时间</strong> 和 <strong>收到消息后前端页面的渲染显示时间</strong></p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221345562.png" alt="image-20230122134511026"></p><h3 id="并发数-1" tabindex="-1">并发数 <a class="header-anchor" href="#并发数-1" aria-label="Permalink to &quot;并发数&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221346997.png" alt="image-20230122134623887" style="zoom:60%;"><h3 id="吞吐量-1" tabindex="-1">吞吐量 <a class="header-anchor" href="#吞吐量-1" aria-label="Permalink to &quot;吞吐量&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221349317.png" alt="image-20230122134939250" style="zoom:67%;"><h3 id="qps" tabindex="-1">QPS <a class="header-anchor" href="#qps" aria-label="Permalink to &quot;QPS&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221416257.png" alt="image-20230122141657211" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221417504.png" alt="image-20230122141736445" style="zoom:67%;"><h3 id="tps" tabindex="-1">TPS <a class="header-anchor" href="#tps" aria-label="Permalink to &quot;TPS&quot;">​</a></h3><blockquote><p>事务：即业务，页面上的一次请求，可能对应一个或多个请求</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221451830.png" alt="image-20230122145122790" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221453409.png" alt="image-20230122145339322"></p><h3 id="点击数" tabindex="-1">点击数 <a class="header-anchor" href="#点击数" aria-label="Permalink to &quot;点击数&quot;">​</a></h3><blockquote><p><strong>只有web项目才有此指标，点击数不是页面上的一次点击</strong></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221455506.png" alt="image-20230122145521462" style="zoom:67%;"><h3 id="错误率" tabindex="-1">错误率 <a class="header-anchor" href="#错误率" aria-label="Permalink to &quot;错误率&quot;">​</a></h3><blockquote><p><strong>大多数系统都会要求错误率无限接近于0，错误率是一个性能指标，不是功能上的随机bug</strong></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221457081.png" alt="image-20230122145727042" style="zoom:67%;"><h3 id="资源利用率" tabindex="-1">资源利用率 <a class="header-anchor" href="#资源利用率" aria-label="Permalink to &quot;资源利用率&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221501454.png" alt="image-20230122150159411" style="zoom:67%;"><p>根据经验，资源指标通常要求</p><blockquote><ul><li>CPU不高于75%-85%</li><li>内存不高于80%</li><li>磁盘IO不高于90%</li><li>网络不高于80%</li></ul></blockquote><h2 id="性能测试流程" tabindex="-1">性能测试流程 <a class="header-anchor" href="#性能测试流程" aria-label="Permalink to &quot;性能测试流程&quot;">​</a></h2><h3 id="整体流程" tabindex="-1">整体流程 <a class="header-anchor" href="#整体流程" aria-label="Permalink to &quot;整体流程&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221512283.png" alt="image-20230122151230212" style="zoom:67%;"><h3 id="需求分析" tabindex="-1">需求分析 <a class="header-anchor" href="#需求分析" aria-label="Permalink to &quot;需求分析&quot;">​</a></h3><h3 id="计划和方案" tabindex="-1">计划和方案 <a class="header-anchor" href="#计划和方案" aria-label="Permalink to &quot;计划和方案&quot;">​</a></h3><blockquote><p>测什么：项目背景，测试目的，测试范围</p><p>谁来测：进度与分工，交付清单</p><p>怎么测：测试策略</p></blockquote><h3 id="性能测试用例" tabindex="-1">性能测试用例 <a class="header-anchor" href="#性能测试用例" aria-label="Permalink to &quot;性能测试用例&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221521462.png" alt="image-20230122152154388" style="zoom:67%;"><h3 id="性能测试执行" tabindex="-1">性能测试执行 <a class="header-anchor" href="#性能测试执行" aria-label="Permalink to &quot;性能测试执行&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221606167.png" alt="image-20230122160615093" style="zoom:67%;"><h3 id="性能测试调优" tabindex="-1">性能测试调优 <a class="header-anchor" href="#性能测试调优" aria-label="Permalink to &quot;性能测试调优&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221607506.png" alt="image-20230122160747462" style="zoom:67%;"><blockquote><p>调优：开发人员为主导，数据库管理员，系统管理员，网络管理员，性能测试分析人员配合进行</p><p>验证：性能测试人员继续进行第二轮，第三轮的测试，与以前的测试结果进行对比，判断调整后系统是否提升</p></blockquote><h1 id="jmeter-压测工具" tabindex="-1">Jmeter 压测工具 <a class="header-anchor" href="#jmeter-压测工具" aria-label="Permalink to &quot;Jmeter 压测工具&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&amp;mid=2247495751&amp;idx=1&amp;sn=dcaa50097b5cac9f85b292df20280e20&amp;chksm=fbcf9d7fccb814699550645081b8776c12dc369d0b18bf3342ac8795d0b1bb6e94151e49ef76&amp;mpshare=1&amp;scene=23&amp;srcid=0511fdLZpWUw8EeMF54TGdLm&amp;sharer_sharetime=1652228096399&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">48张图|手摸手教你性能监控、压测和调优 (qq.com)</a></p><p>性能监控、压测和调优</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111933053.png" alt="image-20220511193342002" style="zoom:80%;"><h2 id="主流性能测试工具" tabindex="-1">主流性能测试工具 <a class="header-anchor" href="#主流性能测试工具" aria-label="Permalink to &quot;主流性能测试工具&quot;">​</a></h2><blockquote><p>日常项目测试JMeter足够用，出商业报告优先Loadrunner</p></blockquote><h3 id="loadrunner" tabindex="-1">Loadrunner <a class="header-anchor" href="#loadrunner" aria-label="Permalink to &quot;Loadrunner&quot;">​</a></h3><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221624517.png" alt="image-20230122162413457"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221624883.png" alt="image-20230122162426837" style="zoom:67%;"><h3 id="jmeter" tabindex="-1">JMeter <a class="header-anchor" href="#jmeter" aria-label="Permalink to &quot;JMeter&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221626375.png" alt="image-20230122162655336" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221627942.png" alt="image-20230122162727905" style="zoom:67%;"><h2 id="jmeter-安装和配置" tabindex="-1">Jmeter 安装和配置 <a class="header-anchor" href="#jmeter-安装和配置" aria-label="Permalink to &quot;Jmeter 安装和配置&quot;">​</a></h2><blockquote><p>先提前装好JDK</p></blockquote><h3 id="下载jmeter-工具" tabindex="-1">下载Jmeter 工具 <a class="header-anchor" href="#下载jmeter-工具" aria-label="Permalink to &quot;下载Jmeter 工具&quot;">​</a></h3><p>下载地址：<a href="https://jmeter.apache.org/download_jmeter.cgi%EF%BC%8CLinux%E6%98%AF%E4%B8%8A%E9%9D%A2%E9%82%A3%E4%B8%AA" target="_blank" rel="noreferrer">https://jmeter.apache.org/download_jmeter.cgi，Linux是上面那个</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111936252.png" alt="image-20220511193632197" style="zoom:80%;"><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 安装JDK</span></span>
<span class="line"><span style="color:#FFCB6B;">sudo</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">apt-get</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">install</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">openjdk-8-jdk</span></span>
<span class="line"><span style="color:#FFCB6B;">java</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-version</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">tar</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-zxvf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">apache-jmeter-5.5.tgz</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/root/apache-jmeter-5.5/bin</span></span>
<span class="line"><span style="color:#FFCB6B;">touch</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">jmeter.log</span></span>
<span class="line"><span style="color:#FFCB6B;">chmod</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">777</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">jmeter.log</span></span>
<span class="line"><span style="color:#FFCB6B;">vim</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/profile</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 配置环境变量</span></span>
<span class="line"><span style="color:#C792EA;">export</span><span style="color:#A6ACCD;"> JMETER_HOME</span><span style="color:#89DDFF;">=</span><span style="color:#C3E88D;">/root/apache-jmeter-5.5</span></span>
<span class="line"><span style="color:#C792EA;">export</span><span style="color:#A6ACCD;"> CLASSPATH</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">$JMETER_HOME</span><span style="color:#C3E88D;">/lib/ext/ApacheJMeter_core.jar:</span><span style="color:#A6ACCD;">$JMETER_HOME</span><span style="color:#C3E88D;">/lib/jorphan.jar:</span><span style="color:#A6ACCD;">$CLASSPATH</span></span>
<span class="line"><span style="color:#C792EA;">export</span><span style="color:#A6ACCD;"> PATH</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">$JMETER_HOME</span><span style="color:#C3E88D;">/bin:</span><span style="color:#A6ACCD;">$PATH</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#82AAFF;">source</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/profile</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">jmeter</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-v</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222029044.png" alt="image-20230122202908958" style="zoom:67%;"><h3 id="修改成中文" tabindex="-1">修改成中文 <a class="header-anchor" href="#修改成中文" aria-label="Permalink to &quot;修改成中文&quot;">​</a></h3><h4 id="临时修改" tabindex="-1">临时修改 <a class="header-anchor" href="#临时修改" aria-label="Permalink to &quot;临时修改&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221651571.png" alt="image-20230122165155516" style="zoom:67%;"><h4 id="永久修改" tabindex="-1">永久修改 <a class="header-anchor" href="#永久修改" aria-label="Permalink to &quot;永久修改&quot;">​</a></h4><blockquote><p>文件在bin目录下</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111940535.png" alt="image-20220511194000485" style="zoom:67%;"><h3 id="修改响应结果乱码" tabindex="-1">修改响应结果乱码 <a class="header-anchor" href="#修改响应结果乱码" aria-label="Permalink to &quot;修改响应结果乱码&quot;">​</a></h3><blockquote><p>修改jmeter.properties文件即可</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># The encoding to be used if none is provided (default ISO-8859-1)</span></span>
<span class="line"><span style="color:#FFCB6B;">sampleresult.default.encoding</span><span style="color:#A6ACCD;">=UTF-8</span></span></code></pre></div><h3 id="运行" tabindex="-1">运行 <a class="header-anchor" href="#运行" aria-label="Permalink to &quot;运行&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221637478.png" alt="image-20230122163707415" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221637117.png" alt="image-20230122163744041" style="zoom:67%;"><h2 id="jmeter-常用目录" tabindex="-1">JMeter 常用目录 <a class="header-anchor" href="#jmeter-常用目录" aria-label="Permalink to &quot;JMeter 常用目录&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221648179.png" alt="image-20230122164831096" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221650307.png" alt="image-20230122165026227"></p><h2 id="元件和组件-⭐" tabindex="-1">元件和组件 ⭐ <a class="header-anchor" href="#元件和组件-⭐" aria-label="Permalink to &quot;元件和组件 ⭐&quot;">​</a></h2><h3 id="元件" tabindex="-1">元件 <a class="header-anchor" href="#元件" aria-label="Permalink to &quot;元件&quot;">​</a></h3><blockquote><p>元件：类似功能组件的容器，类似于Java中的类</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221655189.png" alt="image-20230122165550146" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221657875.png" alt="image-20230122165705792" style="zoom:67%;"><h3 id="组件" tabindex="-1">组件 <a class="header-anchor" href="#组件" aria-label="Permalink to &quot;组件&quot;">​</a></h3><blockquote><p>实现独立的某个功能(类似于类中的方法)</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221701758.png" alt="image-20230122170104662"></p><h3 id="应用场景" tabindex="-1">应用场景 <a class="header-anchor" href="#应用场景" aria-label="Permalink to &quot;应用场景&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221702782.png" alt="image-20230122170245732" style="zoom:67%;"><h3 id="元件的作用域" tabindex="-1">元件的作用域 <a class="header-anchor" href="#元件的作用域" aria-label="Permalink to &quot;元件的作用域&quot;">​</a></h3><blockquote><p>元件的作用域是靠测试计划的树型结构中元件的父子关系来确定的</p><p>所有的组件都是<strong>以取样器为核心</strong>来运行的，组件添加的位置不同，生效的取样器也不同</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221704472.png" alt="image-20230122170423428" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221707474.png" alt="image-20230122170724420" style="zoom:67%;"><h3 id="元件的执行顺序" tabindex="-1">元件的执行顺序 <a class="header-anchor" href="#元件的执行顺序" aria-label="Permalink to &quot;元件的执行顺序&quot;">​</a></h3><blockquote><p>按照测试计划中顺序从上到下依次执行</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221709223.png" alt="image-20230122170906186" style="zoom:67%;"><h2 id="hello-world" tabindex="-1">Hello World <a class="header-anchor" href="#hello-world" aria-label="Permalink to &quot;Hello World&quot;">​</a></h2><blockquote><p>使用JMeter访问百度首页，并查看请求和响应信息</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221712042.png" alt="image-20230122171213000" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221742660.png" alt="image-20230122174218609" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221742757.png" alt="image-20230122174240720" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221742532.png" alt="image-20230122174256466" style="zoom:67%;"><h2 id="线程组-⭐" tabindex="-1">线程组 ⭐ <a class="header-anchor" href="#线程组-⭐" aria-label="Permalink to &quot;线程组 ⭐&quot;">​</a></h2><h3 id="线程组概述" tabindex="-1">线程组概述 <a class="header-anchor" href="#线程组概述" aria-label="Permalink to &quot;线程组概述&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301221827867.png" alt="image-20230122182756779" style="zoom:67%;"><h3 id="线程组分类" tabindex="-1">线程组分类 <a class="header-anchor" href="#线程组分类" aria-label="Permalink to &quot;线程组分类&quot;">​</a></h3><blockquote><p>线程组：普通、常用的线程组，可以看做一个虚拟用户组，线程组中的每一个线程可以当作一个虚拟用户</p><p>setUp线程组：一种特殊类型的线程组，可用于执行预测试操作</p><p>tearDown线程组：一种特殊类型的线程组，可用于执行测试后工作，即最后执行</p></blockquote><h3 id="线程组属性参数" tabindex="-1">线程组属性参数 <a class="header-anchor" href="#线程组属性参数" aria-label="Permalink to &quot;线程组属性参数&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222051140.png" alt="image-20230122205129048" style="zoom:67%;"><h3 id="访问百度-线程组" tabindex="-1">访问百度--线程组 <a class="header-anchor" href="#访问百度-线程组" aria-label="Permalink to &quot;访问百度--线程组&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222053014.png" alt="image-20230122205250352" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222110569.png" alt="image-20230122211022523" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222058775.png" alt="image-20230122205835729" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222059031.png" alt="image-20230122205945995" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222101633.png" alt="image-20230122210105592" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222105872.png" alt="image-20230122210522824" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222108820.png" alt="image-20230122210837775" style="zoom:67%;"><h2 id="http-请求" tabindex="-1">HTTP 请求 <a class="header-anchor" href="#http-请求" aria-label="Permalink to &quot;HTTP 请求&quot;">​</a></h2><h3 id="参数分析" tabindex="-1">参数分析 <a class="header-anchor" href="#参数分析" aria-label="Permalink to &quot;参数分析&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222111597.png" alt="image-20230122211116470" style="zoom:67%;"><h3 id="http-请求案例" tabindex="-1">HTTP 请求案例 <a class="header-anchor" href="#http-请求案例" aria-label="Permalink to &quot;HTTP 请求案例&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222114566.png" alt="image-20230122211401478" style="zoom:50%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222116530.png" alt="image-20230122211636488" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222117454.png" alt="image-20230122211759403" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222118452.png" alt="image-20230122211855401" style="zoom:67%;"><h2 id="参数化" tabindex="-1">参数化 <a class="header-anchor" href="#参数化" aria-label="Permalink to &quot;参数化&quot;">​</a></h2><h3 id="为什么要参数化" tabindex="-1">为什么要参数化 <a class="header-anchor" href="#为什么要参数化" aria-label="Permalink to &quot;为什么要参数化&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222124497.png" alt="image-20230122212456449" style="zoom:67%;"><blockquote><p>参数化测试：把测试数据组织起来，用不同的测试数据调用相同的测试方法</p></blockquote><h3 id="常见的参数化方式" tabindex="-1">常见的参数化方式 <a class="header-anchor" href="#常见的参数化方式" aria-label="Permalink to &quot;常见的参数化方式&quot;">​</a></h3><blockquote><ul><li>用户定义的变量</li><li>用户参数</li><li>CSV Data Set Config</li><li>函数</li></ul></blockquote><h3 id="用户定义的变量" tabindex="-1">用户定义的变量 <a class="header-anchor" href="#用户定义的变量" aria-label="Permalink to &quot;用户定义的变量&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222128098.png" alt="image-20230122212814024" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222130163.png" alt="image-20230122213055097" style="zoom:50%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222129056.png" alt="image-20230122212908981" style="zoom:67%;"><h3 id="用户参数" tabindex="-1">用户参数 <a class="header-anchor" href="#用户参数" aria-label="Permalink to &quot;用户参数&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222133635.png" alt="image-20230122213301103" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222134381.png" alt="image-20230122213420316" style="zoom:67%;"><h3 id="csv数据文件" tabindex="-1">CSV数据文件 <a class="header-anchor" href="#csv数据文件" aria-label="Permalink to &quot;CSV数据文件&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222136642.png" alt="image-20230122213631572" style="zoom:67%;"><blockquote><p>注意：CSV第一行如果带了用户名，密码等表头，忽略首行就要设置成true</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222141572.png" alt="image-20230122214125534" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222139050.png" alt="image-20230122213951990" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222138598.png" alt="image-20230122213859539" style="zoom:67%;"><h3 id="函数方式" tabindex="-1">函数方式 <a class="header-anchor" href="#函数方式" aria-label="Permalink to &quot;函数方式&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222143043.png" alt="image-20230122214309988" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222144273.png" alt="image-20230122214410200" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301222145076.png" alt="image-20230122214504002" style="zoom:67%;"><h2 id="运行-jmeter-程序" tabindex="-1">运行 JMeter 程序 <a class="header-anchor" href="#运行-jmeter-程序" aria-label="Permalink to &quot;运行 JMeter 程序&quot;">​</a></h2><p>打开批处理文件：\apache-jmeter-5.4.3\bin\jmeter.bat。如下图所示</p><p>JMeter安装完了，那我们来一个简单的实验。性能测试当然得有个测试目标，就是被测系统是什么，xmeter君这里就以测度娘为例来描述构造一个简单的性能测试过程：xmeter君保证你在5分钟之内完成一次测试体验。</p><h3 id="添加虚拟用户组" tabindex="-1">添加虚拟用户组 <a class="header-anchor" href="#添加虚拟用户组" aria-label="Permalink to &quot;添加虚拟用户组&quot;">​</a></h3><p>如下图所示，右击“测试计划”&gt;添加&gt;Threads（Users）&gt;线程组。这里xmeter君需要解释一下“线程组”的意思：JMeter是由Java实现的，并且使用一个Java线程来模拟一个用户，因此线程组（Thread Group）就是指一组用户的意思，换句话说一个线程组就是一组虚拟用户（virtual users），这些虚拟用户用来模拟访问被测系统。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207291533896.png" alt="image-20220729153353797" style="zoom:50%;"><h3 id="线程组配置⭐" tabindex="-1">线程组配置⭐ <a class="header-anchor" href="#线程组配置⭐" aria-label="Permalink to &quot;线程组配置⭐&quot;">​</a></h3><p>接下来xmeter君给大家介绍下“线程组”中常用到的一些设置。</p><blockquote><p>1）线程数：这里就是指虚拟用户数，默认的输入是“1”，则表明模拟一个虚拟用户访问被测系统，如果想模拟100个用户，则此处输入100。</p></blockquote><blockquote><p>2）Ramp-Up Period (in seconds): 虚拟用户增长时长。不明白别着急，xmeter君给你举个栗子：比如你测试的是一个考勤系统，那么实际用户登录使用考勤系统的时候并不是大家喊1、2、3 - 走起，然后一起登录。实际使用场景可能是9点钟上班，那么从8:30开始，考勤系统会陆陆续续有人开始登录，直到9:10左右，那么如果完全按照用户的使用场景，设计该测试的时候此处应输入40（分钟）* 60（秒）= 2400。</p><p>但是实际测试一般不会设置如此长的Ramp-Up时间，原因嘛，难道你做一次测试要先等上40分钟做登录操作？一般情况下，可以估计出登录频率最高的时间长度，比如此处可能从8:55到9:00登录的人最多，那这里设置成300秒，如果“线程数”输入为100，则意味着在5分钟内100用户登录完毕。</p><p>Ramp-Up Period=0：代表同时并发</p></blockquote><blockquote><p>3）循环次数：该处设置一个虚拟用户做多少次的测试。默认为1，意味着一个虚拟用户做完一遍事情之后，该虚拟用户停止运行。如果选中“永远”，则意味着测试运行起来之后就根本停不下来了，除非你把它强制咔嚓。</p></blockquote><p><code>1s 内启动 200 个线程，循环次数 100 次。2 w 个请求</code>。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111942777.png" alt="image-20220511194205725" style="zoom:67%;"><h3 id="添加被测页面" tabindex="-1">添加被测页面 <a class="header-anchor" href="#添加被测页面" aria-label="Permalink to &quot;添加被测页面&quot;">​</a></h3><p>接下来的一步就是要加入实际被测页面，右击“线程组” &gt; “添加” &gt; “Sampler” &gt; “HTTP请求”。</p><p>测试 HTTP 请求，如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111944282.png" alt="image-20220511194451219" style="zoom:80%;"><p>配置要测试的协议、服务器地址、端口号。配置信息如下：</p><p>协议：使用 http 协议。</p><p>服务器名称或 IP: www.baidu.com (只是为了演示)。</p><p>端口号：80 端口。</p><p>接下来需要设置一下“HTTP请求” Sampler的属性，如下所示：</p><p>1）名称：输入“百度”，就是被测试网页的描述性文字</p><p>2）服务器名称或IP：被测服务器的网站名字，也可以是IP地址。剩下的属性可以按照被测系统的属性按需配置，现在都可以为空。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207291539804.png" alt="image-20220729153938736" style="zoom:67%;"><p>现在的测试脚本已经可以运行了，先点击下面如图所示的第一步：点击保存脚本按钮；然后点击如图所示的第二步：点击运行测试按钮。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207291540098.png" alt="image-20220729154044023" style="zoom:80%;"><p>等等，xmeter君，为什么我的测试跑完了没啥反应？嗯，其实测试已经跑完了，你可以去“选项” &gt; “Log Viewer”看看运行的日志。如果你还是看不到日志，你可以点击下面所示的三角箭头展开或者收起日志视图。日志视图中可以看到“线程组 1-1”的启动和结束时间，表明测试已经跑完。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207291540362.png" alt="image-20220729154058289" style="zoom:80%;"><p>这JMeter运行看着也太不直观了吧？那如果我的测试有问题了，怎么发现啊？别着急，JMeter提供了“监听器”让用户来观察测试结果。</p><h3 id="查看结果树" tabindex="-1">查看结果树 <a class="header-anchor" href="#查看结果树" aria-label="Permalink to &quot;查看结果树&quot;">​</a></h3><p>如下图所示，右击“线程组” &gt; “监听器” &gt; “察看结果树”来查看性能测试过程中请求和响应信息。添加完毕后，保存测试脚本，再次运行。</p><p>添加查看结果树、汇总报告和聚合报告。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111947296.png" alt="image-20220511194704231" style="zoom:80%;"><h4 id="开始压力测试" tabindex="-1">开始压力测试 <a class="header-anchor" href="#开始压力测试" aria-label="Permalink to &quot;开始压力测试&quot;">​</a></h4><p>点击播放按钮就开始启动了。注意启动之前需要先设置线程组的参数配置和 HTTP 请求的配置。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111947724.png" alt="image-20220511194739676" style="zoom:80%;"><p>查看每个请求结果，如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111949111.png" alt="image-20220511194900059" style="zoom:80%;"><h4 id="查看汇总报告" tabindex="-1">查看汇总报告 <a class="header-anchor" href="#查看汇总报告" aria-label="Permalink to &quot;查看汇总报告&quot;">​</a></h4><p>主要关心平均值和吞吐量。</p><p>200 个线程，每个线程调用 100 次，总共 2 w 次，可以看到下图中表格中的样本列也是 2 w，请求所耗费的时间是 151 ms，吞吐量是 880 个请求每秒。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205111952838.png" alt="image-20220511195253788" style="zoom:80%;"><h4 id="查看聚合报告" tabindex="-1">查看聚合报告 <a class="header-anchor" href="#查看聚合报告" aria-label="Permalink to &quot;查看聚合报告&quot;">​</a></h4><p>主要看中位数和90%百分位，</p><p><strong>中位数</strong>是 59 ms，说明大部分请求的响应时间是 59 ms。</p><p><strong>90 % 的请求</strong> 都是在 271 ms 以内响应完成的。</p><p><strong>异常 0.41%</strong> 说明 2 w 个请求中有 82 个请求异常（20000 * 0.0041 = 82 ）。</p><p><strong>吞吐量 880.2/sec</strong> 说明百度这个网站每秒能处理 880 个请求，性能一般（可能跟本地机器性能有关）。</p><p>如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112013113.png" alt="image-20220511201316061" style="zoom:80%;"><h4 id="查看汇总图" tabindex="-1">查看汇总图 <a class="header-anchor" href="#查看汇总图" aria-label="Permalink to &quot;查看汇总图&quot;">​</a></h4><p>查看汇总图时，需要先勾选想要查看的信息，如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112013657.png" alt="image-20220511201301593" style="zoom:80%;"><p>然后查看图形汇总：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112012372.png" alt="image-20220511201243323" style="zoom:80%;"><p>可以看到勾选的几列在图表中是用不同颜色表示的，比如绿色的柱状条就是 90 % 百分位。</p><p>我们来测试下 PassJava（佳必过）的管理后台的性能，吞吐量接近 2000/s。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205112012376.png" alt="image-20220511201227325" style="zoom:80%;"><h1 id="断言" tabindex="-1">断言 <a class="header-anchor" href="#断言" aria-label="Permalink to &quot;断言&quot;">​</a></h1><h2 id="为什么要用断言" tabindex="-1">为什么要用断言 <a class="header-anchor" href="#为什么要用断言" aria-label="Permalink to &quot;为什么要用断言&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231131107.png" alt="image-20230123113116054" style="zoom:67%;"><h2 id="响应断言" tabindex="-1">响应断言 <a class="header-anchor" href="#响应断言" aria-label="Permalink to &quot;响应断言&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231133832.png" alt="image-20230123113355737" style="zoom:67%;"><h3 id="测试字段-实际结果" tabindex="-1">测试字段-实际结果 <a class="header-anchor" href="#测试字段-实际结果" aria-label="Permalink to &quot;测试字段-实际结果&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231135649.png" alt="image-20230123113557602" style="zoom:67%;"><h3 id="模式匹配规则-比较方式" tabindex="-1">模式匹配规则-比较方式 <a class="header-anchor" href="#模式匹配规则-比较方式" aria-label="Permalink to &quot;模式匹配规则-比较方式&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231137558.png" alt="image-20230123113742498" style="zoom:60%;"><h3 id="预期结果" tabindex="-1">预期结果 <a class="header-anchor" href="#预期结果" aria-label="Permalink to &quot;预期结果&quot;">​</a></h3><blockquote><p>即填写你指定的结果(可填写多个)，按钮【添加】、【删除】是进行指定内容的管理</p></blockquote><h3 id="案例练习" tabindex="-1">案例练习 <a class="header-anchor" href="#案例练习" aria-label="Permalink to &quot;案例练习&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231141006.png" alt="image-20230123114103939" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231146421.png" alt="image-20230123114612350" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231146428.png" alt="image-20230123114649365" style="zoom:67%;"><h2 id="json断言" tabindex="-1">JSON断言 <a class="header-anchor" href="#json断言" aria-label="Permalink to &quot;JSON断言&quot;">​</a></h2><h3 id="语法详解" tabindex="-1">语法详解 <a class="header-anchor" href="#语法详解" aria-label="Permalink to &quot;语法详解&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231149336.png" alt="image-20230123114933242" style="zoom:67%;"><h3 id="案例练习-1" tabindex="-1">案例练习 <a class="header-anchor" href="#案例练习-1" aria-label="Permalink to &quot;案例练习&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231151168.png" alt="image-20230123115106531" style="zoom:50%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231204115.png" alt="image-20230123120411056" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231204838.png" alt="image-20230123120440783" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231205515.png" alt="image-20230123120505478"></p><h2 id="断言持续时间" tabindex="-1">断言持续时间 <a class="header-anchor" href="#断言持续时间" aria-label="Permalink to &quot;断言持续时间&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231206403.png" alt="image-20230123120629336" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231207185.png" alt="image-20230123120724119" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231209751.png" alt="image-20230123120904695" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231209075.png" alt="image-20230123120938024" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231210472.png" alt="image-20230123121002416" style="zoom:67%;"><h1 id="关联" tabindex="-1">关联 <a class="header-anchor" href="#关联" aria-label="Permalink to &quot;关联&quot;">​</a></h1><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231213472.png" alt="image-20230123121324405" style="zoom:60%;"><h2 id="什么是关联" tabindex="-1">什么是关联 <a class="header-anchor" href="#什么是关联" aria-label="Permalink to &quot;什么是关联&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231214614.png" alt="image-20230123121456564" style="zoom:67%;"><blockquote><p>常用关联方法：正则表达式提取器、XPATH提取器、JSON提取器</p></blockquote><h2 id="正则表达式提取器" tabindex="-1">正则表达式提取器 <a class="header-anchor" href="#正则表达式提取器" aria-label="Permalink to &quot;正则表达式提取器&quot;">​</a></h2><h3 id="基本语法" tabindex="-1">基本语法 <a class="header-anchor" href="#基本语法" aria-label="Permalink to &quot;基本语法&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231217918.png" alt="image-20230123121748820" style="zoom:67%;"><h3 id="案例练习-2" tabindex="-1">案例练习 <a class="header-anchor" href="#案例练习-2" aria-label="Permalink to &quot;案例练习&quot;">​</a></h3><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231219469.png" alt="image-20230123121936385"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231224874.png" alt="image-20230123122420802" style="zoom:67%;"><blockquote><p><strong>模板表示匹配第几个(.*?)，因为表达式可能有多个(.*?)进行匹配</strong></p><p><strong>匹配数字很重要，因为可能会匹配很多个数据，匹配数字表示选择第几个，-1表示获取所有结果</strong></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231225466.png" alt="image-20230123122507402" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231225114.png" alt="image-20230123122533050" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231225509.png" alt="image-20230123122556435" style="zoom:67%;"><p>其他案例</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231228966.png" alt="image-20230123122805921" style="zoom:80%;"><h2 id="xpath提取器" tabindex="-1">XPATH提取器 <a class="header-anchor" href="#xpath提取器" aria-label="Permalink to &quot;XPATH提取器&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231240611.png" alt="image-20230123124003447" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231240328.png" alt="image-20230123124049228" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231246553.png" alt="image-20230123124640477"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231247362.png" alt="image-20230123124747294" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231248006.png" alt="image-20230123124805941" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231248108.png" alt="image-20230123124827670"></p><h2 id="json-提取器" tabindex="-1">JSON 提取器 <a class="header-anchor" href="#json-提取器" aria-label="Permalink to &quot;JSON 提取器&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231249581.png" alt="image-20230123124938496" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231251657.png" alt="image-20230123125103576" style="zoom:60%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231253311.png" alt="image-20230123125358248" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231254340.png" alt="image-20230123125414258" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231254459.png" alt="image-20230123125430379" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231254154.png" alt="image-20230123125450086" style="zoom:80%;"><h2 id="jmeter-属性" tabindex="-1">JMeter 属性 <a class="header-anchor" href="#jmeter-属性" aria-label="Permalink to &quot;JMeter 属性&quot;">​</a></h2><h3 id="为什么要用" tabindex="-1">为什么要用 <a class="header-anchor" href="#为什么要用" aria-label="Permalink to &quot;为什么要用&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231256675.png" alt="image-20230123125617615" style="zoom:67%;"><h3 id="配置函数" tabindex="-1">配置函数 <a class="header-anchor" href="#配置函数" aria-label="Permalink to &quot;配置函数&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231345454.png" alt="image-20230123134504358" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231345064.png" alt="image-20230123134549997" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231359372.png" alt="image-20230123135909298" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231359701.png" alt="image-20230123135931640" style="zoom:67%;"><p>工具----&gt;函数对话框</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231351411.png" alt="image-20230123135135344" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231400010.png" alt="image-20230123140000944" style="zoom:67%;"><blockquote><p>另一个线程组</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231400257.png" alt="image-20230123140024191" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231400512.png" alt="image-20230123140046448" style="zoom:67%;"><h1 id="脚本录制" tabindex="-1">脚本录制 <a class="header-anchor" href="#脚本录制" aria-label="Permalink to &quot;脚本录制&quot;">​</a></h1><h2 id="jmeter-录制脚本" tabindex="-1">JMeter 录制脚本 <a class="header-anchor" href="#jmeter-录制脚本" aria-label="Permalink to &quot;JMeter 录制脚本&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231402856.png" alt="image-20230123140218766" style="zoom:67%;"><h2 id="录制脚本过程" tabindex="-1">录制脚本过程 <a class="header-anchor" href="#录制脚本过程" aria-label="Permalink to &quot;录制脚本过程&quot;">​</a></h2><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231405636.png" alt="image-20230123140539470"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231406910.png" alt="image-20230123140620720" style="zoom:67%;"><h2 id="实战演示" tabindex="-1">实战演示 <a class="header-anchor" href="#实战演示" aria-label="Permalink to &quot;实战演示&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231408634.png" alt="image-20230123140834585" style="zoom:67%;"><h1 id="直连数据库" tabindex="-1">直连数据库 <a class="header-anchor" href="#直连数据库" aria-label="Permalink to &quot;直连数据库&quot;">​</a></h1><h2 id="使用场景" tabindex="-1">使用场景 <a class="header-anchor" href="#使用场景" aria-label="Permalink to &quot;使用场景&quot;">​</a></h2><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231042675.png" alt="image-20230123104213585"></p><h2 id="关键配置" tabindex="-1">关键配置 <a class="header-anchor" href="#关键配置" aria-label="Permalink to &quot;关键配置&quot;">​</a></h2><h3 id="mysql-connector-java" tabindex="-1">mysql-connector-java <a class="header-anchor" href="#mysql-connector-java" aria-label="Permalink to &quot;mysql-connector-java&quot;">​</a></h3><p>指导网站：<a href="https://blog.csdn.net/T_Y_F_/article/details/125194749" target="_blank" rel="noreferrer">https://blog.csdn.net/T_Y_F_/article/details/125194749</a></p><p>下载地址：<a href="https://downloads.mysql.com/archives/c-j/" target="_blank" rel="noreferrer">https://downloads.mysql.com/archives/c-j/</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231055132.png" alt="image-20230123105457432" style="zoom:50%;"><p>添加MySQL Jar包</p><blockquote><p>方式一：在测试计划面板点击浏览按钮，将你的JDBC驱动添加进来 当前线程组有效</p><p>方式二：将MySQL驱动jar包放在lib/ext目录下，重启JMeter 全部有效</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231053320.png" alt="image-20230123105351228" style="zoom:67%;"><blockquote><p>配置数据库连接：添加方式：测试计划--线程组--配置元件---JDBC Connection Configuration</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231101742.png" alt="image-20230123110146668" style="zoom:50%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231113507.png" alt="image-20230123111310421" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231109553.png" alt="image-20230123110910488" style="zoom:50%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231114448.png" alt="image-20230123111407364" style="zoom:50%;"><blockquote><p>直接启动即可</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231115503.png" alt="image-20230123111512440" style="zoom:67%;"><h2 id="添加jdbc请求" tabindex="-1">添加JDBC请求 <a class="header-anchor" href="#添加jdbc请求" aria-label="Permalink to &quot;添加JDBC请求&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231104767.png" alt="image-20230123110440686" style="zoom:67%;"><h2 id="搜索结果断言" tabindex="-1">搜索结果断言 <a class="header-anchor" href="#搜索结果断言" aria-label="Permalink to &quot;搜索结果断言&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231411198.png" alt="image-20230123141140091" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231413977.png" alt="image-20230123141329863"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231415729.png" alt="image-20230123141457599"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231417029.png" alt="image-20230123141611422"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231417311.png" alt="image-20230123141759234" style="zoom:67%;"><h1 id="控制器" tabindex="-1">控制器 <a class="header-anchor" href="#控制器" aria-label="Permalink to &quot;控制器&quot;">​</a></h1><h2 id="循环控制器" tabindex="-1">循环控制器 <a class="header-anchor" href="#循环控制器" aria-label="Permalink to &quot;循环控制器&quot;">​</a></h2><blockquote><p>连续访问百度10次</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231422810.png" alt="image-20230123142227752" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231423131.png" alt="image-20230123142300068" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231423343.png" alt="image-20230123142315268" style="zoom:67%;"><h2 id="if-控制器" tabindex="-1">IF 控制器 <a class="header-anchor" href="#if-控制器" aria-label="Permalink to &quot;IF 控制器&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231424674.png" alt="image-20230123142459572" style="zoom:60%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231426348.png" alt="image-20230123142647276" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231429590.png" alt="image-20230123142900525"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231429597.png" alt="image-20230123142936484"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231430070.png" alt="image-20230123143011955" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231430396.png" alt="image-20230123143053300"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231431042.png" alt="image-20230123143112951" style="zoom:67%;"><h2 id="foreach-控制器" tabindex="-1">Foreach 控制器 <a class="header-anchor" href="#foreach-控制器" aria-label="Permalink to &quot;Foreach 控制器&quot;">​</a></h2><h3 id="基本语法-1" tabindex="-1">基本语法 <a class="header-anchor" href="#基本语法-1" aria-label="Permalink to &quot;基本语法&quot;">​</a></h3><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231433515.png" alt="image-20230123143313421"></p><h3 id="案例演示" tabindex="-1">案例演示 <a class="header-anchor" href="#案例演示" aria-label="Permalink to &quot;案例演示&quot;">​</a></h3><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231433340.png" alt="image-20230123143357246"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231438471.png" alt="image-20230123143847413" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231438647.png" alt="image-20230123143831579" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231439232.png" alt="image-20230123143903166" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231439308.png" alt="image-20230123143928246" style="zoom:67%;"><h3 id="案例演示2" tabindex="-1">案例演示2 <a class="header-anchor" href="#案例演示2" aria-label="Permalink to &quot;案例演示2&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231441317.png" alt="image-20230123144104207" style="zoom:50%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231448045.png" alt="image-20230123144828983" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231448762.png" alt="image-20230123144846697"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231448605.png" alt="image-20230123144858548"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231449933.png" alt="image-20230123144908871" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231449772.png" alt="image-20230123144927703" style="zoom:67%;"><h1 id="定时器" tabindex="-1">定时器 <a class="header-anchor" href="#定时器" aria-label="Permalink to &quot;定时器&quot;">​</a></h1><h2 id="同步定时器" tabindex="-1">同步定时器 <a class="header-anchor" href="#同步定时器" aria-label="Permalink to &quot;同步定时器&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231527780.png" alt="image-20230123152743715" style="zoom:50%;"><h3 id="什么是同步定时器" tabindex="-1">什么是同步定时器 <a class="header-anchor" href="#什么是同步定时器" aria-label="Permalink to &quot;什么是同步定时器&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231528281.png" alt="image-20230123152851150" style="zoom:50%;"><h3 id="如何使用" tabindex="-1">如何使用 <a class="header-anchor" href="#如何使用" aria-label="Permalink to &quot;如何使用&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231529898.png" alt="image-20230123152948804" style="zoom:60%;"><h3 id="案例演示-1" tabindex="-1">案例演示 <a class="header-anchor" href="#案例演示-1" aria-label="Permalink to &quot;案例演示&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231530919.png" alt="image-20230123153053845" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231534014.png" alt="image-20230123153433950" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231534019.png" alt="image-20230123153445965" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231534985.png" alt="image-20230123153457919" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231535613.png" alt="image-20230123153506539"></p><h2 id="常数吞吐量定时器" tabindex="-1">常数吞吐量定时器 <a class="header-anchor" href="#常数吞吐量定时器" aria-label="Permalink to &quot;常数吞吐量定时器&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231538935.png" alt="image-20230123153817878" style="zoom:67%;"><h3 id="使用方法" tabindex="-1">使用方法 <a class="header-anchor" href="#使用方法" aria-label="Permalink to &quot;使用方法&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231540224.png" alt="image-20230123154040130" style="zoom:60%;"><h3 id="案例演示-2" tabindex="-1">案例演示 <a class="header-anchor" href="#案例演示-2" aria-label="Permalink to &quot;案例演示&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231541839.png" alt="image-20230123154138769" style="zoom:60%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231544097.png" alt="image-20230123154458032" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231545204.png" alt="image-20230123154510136" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231545768.png" alt="image-20230123154523712" style="zoom:67%;"><h2 id="固定定时器" tabindex="-1">固定定时器 <a class="header-anchor" href="#固定定时器" aria-label="Permalink to &quot;固定定时器&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231550395.png" alt="image-20230123155003327" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231552095.png" alt="image-20230123155223040" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.2.30/202301231553211.png" alt="image-20230123155313159" style="zoom:67%;"></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-37656e44><!--[--><!--]--><!----><nav class="prev-next" data-v-37656e44><div class="pager" data-v-37656e44><!----></div><div class="pager" data-v-37656e44><a class="pager-link next" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-37656e44><span class="desc" data-v-37656e44>Next page</span><span class="title" data-v-37656e44>Java基础</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"2、数据库_mysql_mysql面试_基础.md\":\"40da680a\",\"1、学前端_5、小程序_小程序项目.md\":\"60a1629b\",\"1、学前端_4、node_知识篇.md\":\"a7fb500e\",\"1、学前端_2、js_ts_es6 进阶.md\":\"6d07ba10\",\"1、学前端_3、vue_vue3_vue3进阶.md\":\"7ac622b4\",\"5、运维_jenkins.md\":\"929081f8\",\"1、学前端_2、js_ts_typescript.md\":\"875a4aa4\",\"2、数据库_mysql_mysql核心_设计.md\":\"7faf46d1\",\"2、数据库_mysql_mysql核心_基础.md\":\"d8e97f3e\",\"1、学前端_1、html_css_html基础.md\":\"7584d076\",\"1、学前端_5、专题篇_问题篇.md\":\"e893aaa2\",\"2、数据库_mysql_mysql面试_进阶.md\":\"f934806d\",\"3、springboot_运维_原理.md\":\"f4a39db6\",\"2、数据库_influxdb.md\":\"6e1711e1\",\"3、springboot_新特性.md\":\"cdf3e307\",\"mybatis_mybatisplus_jpa.md\":\"8e41681b\",\"1、学前端_5、小程序_小程序优化.md\":\"a2185198\",\"2、数据库_redis_redis基础.md\":\"856df0e0\",\"linux_实用脚本.md\":\"f2299dd5\",\"4、微服务_必备_分布式基础.md\":\"d49863d5\",\"2、数据库_redis_redis优化.md\":\"e66ae32f\",\"4、微服务_springsecurity_进阶篇.md\":\"235a8e9e\",\"5、运维_chatgpt.md\":\"10db3823\",\"2、数据库_mysql_分库分表.md\":\"e1c8a095\",\"start.md\":\"9bc1ff8d\",\"5、运维_github.md\":\"2ec6c735\",\"java学前端_css.md\":\"f11b47f0\",\"1、学前端_5、专题篇_知识篇.md\":\"a463ed8d\",\"linux_软件部署.md\":\"d6722925\",\"2、数据库_neo4j.md\":\"97ad22ac\",\"team.md\":\"ce467a6a\",\"nginx_实战篇.md\":\"7785486e\",\"index.md\":\"8c3ec167\",\"计算机基础_计算机网络_网络基础.md\":\"7a54a85d\",\"1、学前端_4、node_进阶篇.md\":\"60f6db69\",\"java_java集合.md\":\"a049b313\",\"1、学前端_3、vue_vue3_vue3高级.md\":\"614d1516\",\"1、学前端_5、小程序_微信小程序.md\":\"9a4be771\",\"5、运维_netty.md\":\"12ca0278\",\"2、数据库_mysql_mysql核心_运维.md\":\"83f97c16\",\"idea_vs code.md\":\"afdcb593\",\"java学前端_vue3_组件.md\":\"1086884e\",\"idea_chrome.md\":\"4a32afbc\",\"云原生_k8s.md\":\"db58e65a\",\"2、数据库_mysql_mysql核心_进阶.md\":\"61d16dff\",\"ssm_springbatch.md\":\"f799ab4a\",\"三高_分布式.md\":\"db1b8a1b\",\"2、数据库_elasticsearch_1、es基础.md\":\"04d17448\",\"linux_linux基础.md\":\"4b0bf394\",\"idea_idea插件.md\":\"fa86e45a\",\"可视化 _ 监控_可视化大屏.md\":\"004553bd\",\"2、数据库_mongodb_整合.md\":\"3c47d7f4\",\"4、微服务_springsecurity_基础篇.md\":\"534a3401\",\"4、微服务_进阶.md\":\"69095c58\",\"计算机基础_计算机基础_操作系统.md\":\"0f75d113\",\"可视化 _ 监控_zabbix.md\":\"71f2270e\",\"nginx_基础篇.md\":\"c7d8bb50\",\"1、学前端_4、node_项目实战.md\":\"bc5065b8\",\"2、数据库_redis_redis原理.md\":\"5cedf685\",\"可视化 _ 监控_监控基础.md\":\"ac56ce4d\",\"三高_高并发.md\":\"ea9ffc99\",\"2、数据库_redis_redis高级.md\":\"1d5872f6\",\"1、学前端_4、node_基础篇.md\":\"581cc13a\",\"2、数据库_mongodb_基础.md\":\"fb7a0a29\",\"idea_idea基础.md\":\"6f2f9638\",\"4、微服务_必备_sentinel.md\":\"2edfbf6c\",\"2、数据库_elasticsearch_3、es高级.md\":\"ef146606\",\"1、学前端_3、vue_vue3_vue3新语法.md\":\"8afd5409\",\"消息中间件_canal.md\":\"3949163c\",\"ssm_maven.md\":\"2c5e12ed\",\"4、微服务_springsecurity_高级篇.md\":\"882d3ff3\",\"linux_linux进阶.md\":\"188ef7b4\",\"计算机基础_设计模式_uml.md\":\"634ba256\",\"计算机基础_算法_leetcode.md\":\"77162fb9\",\"项目实战_小兔鲜_进阶篇1.md\":\"17c52c81\",\"1、学前端_2、js_ts_es6 基础.md\":\"fda3f18b\",\"项目实战_小兔鲜_进阶篇2.md\":\"a0f23006\",\"软件测试_测试基础.md\":\"8c1060cd\",\"2、数据库_redis_本地缓存.md\":\"00617fe6\",\"nginx_面试篇.md\":\"e3fb373a\",\"mybatis_mybatisplus_mybatis.md\":\"9239e0ad\",\"linux_shell.md\":\"ae53d83b\",\"2、数据库_mysql_mysql核心_优化.md\":\"36230425\",\"项目实战_项目推荐.md\":\"f9d97630\",\"mybatis_mybatisplus_mybatisplus.md\":\"0030fd35\",\"项目实战_百度地图_进阶篇.md\":\"c8b93267\",\"三高_高可用.md\":\"323840c5\",\"java_java新特性.md\":\"22abf56d\",\"软件测试_压力测试.md\":\"9ab44440\",\"java学前端_html_js.md\":\"e0fcd240\",\"2、数据库_redis_redis实战.md\":\"d6daeeab\",\"nginx_进阶篇.md\":\"e6b63195\",\"三高_秒杀.md\":\"3878bb64\",\"5、运维_git.md\":\"0264925c\",\"java_java进阶.md\":\"e79cb5b4\",\"并发 _ 多线程_基础篇.md\":\"7adbfac5\",\"项目实战_百度地图_基础篇.md\":\"8afa5954\",\"java学前端_react.md\":\"3ec827dd\",\"1、学前端_1、html_css_css基础.md\":\"01b56712\",\"项目实战_小兔鲜_基础篇.md\":\"646f5df5\",\"1、学前端_2、js_ts_js 基础.md\":\"cb13e36f\",\"可视化 _ 监控_监控进阶.md\":\"0cdbc292\",\"计算机基础_设计模式_基础篇.md\":\"51617287\",\"计算机基础_数据结构_基础篇.md\":\"b2bfd8d4\",\"项目实战_苍穹外卖_进阶篇.md\":\"48415e41\",\"ssm_spring.md\":\"ab514659\",\"消息中间件_rabbitmq.md\":\"45b1eb28\",\"1、学前端_1、html_css_网页进阶.md\":\"db998248\",\"消息中间件_kafka.md\":\"b747dabf\",\"云原生_docker.md\":\"983c7ba7\",\"4、微服务_必备_分布式锁.md\":\"5af1cf8d\",\"消息中间件_rocketmq.md\":\"d441da85\",\"项目实战_黑马头条_基础篇.md\":\"b05af3a6\",\"ssm_springmvc.md\":\"81b9714f\",\"项目实战_支付.md\":\"1d7407dd\",\"项目实战_黑马头条_进阶篇2.md\":\"bff0015b\",\"项目实战_黑马头条_进阶篇.md\":\"19f18388\",\"java学前端_vue2_组件.md\":\"58c6b1df\",\"3、springboot_基础篇.md\":\"529c66f4\",\"3、springboot_应用篇.md\":\"8b92aa61\",\"项目实战_黑马头条_高级篇.md\":\"227c08c1\",\"1、学前端_5、小程序_uniapp.md\":\"71a282b4\",\"项目实战_云尚办公_基础篇.md\":\"1fe188ba\",\"并发 _ 多线程_并发完善.md\":\"26619c46\",\"1、学前端_2、js_ts_js 进阶.md\":\"657dfb8f\",\"java_java高级.md\":\"23782d1a\",\"java_java基础.md\":\"86d67c77\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"VitePress\",\"description\":\"A VitePress site\",\"base\":\"/notebook/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"algolia\":{\"appId\":\"DW7O63I9IR\",\"apiKey\":\"f8ed758cdb288a8b06542bc35923c1a1\",\"indexName\":\"notebook\"},\"sidebar\":[{\"text\":\"Java\",\"collapsed\":true,\"items\":[{\"text\":\"Java基础\",\"link\":\"/Java/Java基础\"},{\"text\":\"Java新特性\",\"link\":\"/Java/Java新特性\"},{\"text\":\"Java进阶\",\"link\":\"/Java/Java进阶\"},{\"text\":\"Java集合\",\"link\":\"/Java/Java集合\"},{\"text\":\"Java高级\",\"link\":\"/Java/Java高级\"}]},{\"text\":\"Linux\",\"collapsed\":true,\"items\":[{\"text\":\"Linux基础\",\"link\":\"/Linux/Linux基础\"},{\"text\":\"Linux新特性\",\"link\":\"/Linux/Linux进阶\"},{\"text\":\"Shell脚本\",\"link\":\"/Linux/Shell\"},{\"text\":\"实用脚本\",\"link\":\"/Linux/实用脚本\"},{\"text\":\"软件部署\",\"link\":\"/Linux/软件部署\"}]},{\"text\":\"Nginx\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/Nginx/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/Nginx/进阶篇\"},{\"text\":\"实战篇\",\"link\":\"/Nginx/实战篇\"},{\"text\":\"面试篇\",\"link\":\"/Nginx/面试篇\"}]},{\"text\":\"SSM\",\"collapsed\":true,\"items\":[{\"text\":\"Maven\",\"link\":\"/SSM/Maven\"},{\"text\":\"Spring\",\"link\":\"/SSM/Spring\"},{\"text\":\"SpringMVC\",\"link\":\"/SSM/SpringMVC\"},{\"text\":\"SpringBatch\",\"link\":\"/SSM/SpringBatch\"}]},{\"text\":\"SpringBoot\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/3、SpringBoot/基础篇\"},{\"text\":\"应用篇\",\"link\":\"/3、SpringBoot/应用篇\"},{\"text\":\"新特性\",\"link\":\"/3、SpringBoot/新特性\"},{\"text\":\"运维&原理\",\"link\":\"/3、SpringBoot/运维&原理\"}]},{\"text\":\"SpringCloud\",\"collapsed\":true,\"items\":[{\"text\":\"SpringCloud\",\"link\":\"/4、微服务/进阶\"},{\"text\":\"Sentinel\",\"link\":\"/4、微服务/必备/Sentinel\"}]},{\"text\":\"SpringSecurity\",\"collapsed\":true,\"items\":[{\"text\":\"SpringSecurity基础篇\",\"link\":\"/4、微服务/SpringSecurity/基础篇\"},{\"text\":\"SpringSecurity进阶篇\",\"link\":\"/4、微服务/SpringSecurity/进阶篇\"},{\"text\":\"SpringSecurity高级篇\",\"link\":\"/4、微服务/SpringSecurity/高级篇\"}]},{\"text\":\"Mybatis & MybatisPlus\",\"collapsed\":true,\"items\":[{\"text\":\"Mybatis\",\"link\":\"/Mybatis&MybatisPlus/Mybatis\"},{\"text\":\"MybatisPlus\",\"link\":\"/Mybatis&MybatisPlus/MybatisPlus\"},{\"text\":\"JPA\",\"link\":\"/Mybatis&MybatisPlus/JPA\"}]},{\"text\":\"Git & ChatGPT\",\"collapsed\":true,\"items\":[{\"text\":\"Git\",\"link\":\"/5、运维/Git\"},{\"text\":\"Github\",\"link\":\"/5、运维/Github\"},{\"text\":\"ChatGPT\",\"link\":\"/5、运维/ChatGPT\"},{\"text\":\"Jenkins\",\"link\":\"/5、运维/Jenkins\"},{\"text\":\"Netty\",\"link\":\"/5、运维/Netty\"}]},{\"text\":\"数据库\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL基础\",\"link\":\"/2、数据库/MySQL/MySQL核心/基础\"},{\"text\":\"MySQL进阶\",\"link\":\"/2、数据库/MySQL/MySQL核心/进阶\"},{\"text\":\"MySQL优化\",\"link\":\"/2、数据库/MySQL/MySQL核心/优化\"},{\"text\":\"MySQL设计\",\"link\":\"/2、数据库/MySQL/MySQL核心/设计\"},{\"text\":\"MySQL运维\",\"link\":\"/2、数据库/MySQL/MySQL核心/运维\"},{\"text\":\"分库分表\",\"link\":\"/2、数据库/MySQL/分库分表\"}]},{\"text\":\"Redis\",\"collapsed\":true,\"items\":[{\"text\":\"Redis基础\",\"link\":\"/2、数据库/Redis/Redis基础\"},{\"text\":\"Redis优化\",\"link\":\"/2、数据库/Redis/Redis优化\"},{\"text\":\"Redis原理\",\"link\":\"/2、数据库/Redis/Redis原理\"},{\"text\":\"Redis高级\",\"link\":\"/2、数据库/Redis/Redis高级\"},{\"text\":\"Redis实战\",\"link\":\"/2、数据库/Redis/Redis实战\"},{\"text\":\"本地缓存\",\"link\":\"/2、数据库/Redis/本地缓存\"}]},{\"text\":\"MongoDB\",\"collapsed\":true,\"items\":[{\"text\":\"MongoDB基础\",\"link\":\"/2、数据库/MongoDB/基础\"},{\"text\":\"MongoDB进阶\",\"link\":\"/2、数据库/MongoDB/整合\"}]},{\"text\":\"ElasticSearch\",\"collapsed\":true,\"items\":[{\"text\":\"ES基础\",\"link\":\"/2、数据库/ElasticSearch/1、ES基础\"},{\"text\":\"ES高级\",\"link\":\"/2、数据库/ElasticSearch/3、ES高级\"}]},{\"text\":\"InfluxDB\",\"link\":\"/2、数据库/influxdb\"},{\"text\":\"Neo4j\",\"link\":\"/2、数据库/Neo4j\"}]},{\"text\":\"高并发 & 秒杀 & 分布式\",\"collapsed\":true,\"items\":[{\"text\":\"分布式理论\",\"link\":\"/三高/分布式\"},{\"text\":\"分布式锁\",\"link\":\"/4、微服务/必备/分布式锁\"},{\"text\":\"秒杀\",\"link\":\"/三高/秒杀\"},{\"text\":\"高可用\",\"link\":\"/三高/高可用\"},{\"text\":\"高并发\",\"link\":\"/三高/高并发\"}]},{\"text\":\"云原生\",\"collapsed\":true,\"items\":[{\"text\":\"Docker\",\"link\":\"/云原生/Docker\"},{\"text\":\"K8S\",\"link\":\"/云原生/K8S\"}]},{\"text\":\"可视化 & 监控\",\"collapsed\":true,\"items\":[{\"text\":\"监控基础\",\"link\":\"/可视化 & 监控/监控基础\"},{\"text\":\"监控进阶\",\"link\":\"/可视化 & 监控/监控进阶\"},{\"text\":\"可视化大屏\",\"link\":\"/可视化 & 监控/可视化大屏\"},{\"text\":\"Zabbix\",\"link\":\"/可视化 & 监控/Zabbix\"}]},{\"text\":\"学前端\",\"collapsed\":true,\"items\":[{\"text\":\"HTML+CSS\",\"collapsed\":true,\"items\":[{\"text\":\"HTML基础\",\"link\":\"/1、学前端/1、HTML+CSS/HTML基础\"},{\"text\":\"CSS基础\",\"link\":\"/1、学前端/1、HTML+CSS/CSS基础\"},{\"text\":\"网页进阶\",\"link\":\"/1、学前端/1、HTML+CSS/网页进阶\"}]},{\"text\":\"JS+TS\",\"collapsed\":true,\"items\":[{\"text\":\"JS基础\",\"link\":\"/1、学前端/2、JS+TS/JS 基础\"},{\"text\":\"JS进阶\",\"link\":\"/1、学前端/2、JS+TS/JS 进阶\"},{\"text\":\"ES6基础\",\"link\":\"/1、学前端/2、JS+TS/ES6 基础\"},{\"text\":\"ES6进阶\",\"link\":\"/1、学前端/2、JS+TS/ES6 进阶\"},{\"text\":\"TS基础\",\"link\":\"/1、学前端/2、JS+TS/TypeScript\"}]},{\"text\":\"NodeJS\",\"collapsed\":true,\"items\":[{\"text\":\"Node基础\",\"link\":\"/1、学前端/4、Node/基础篇\"},{\"text\":\"Node进阶\",\"link\":\"/1、学前端/4、Node/进阶篇\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/4、Node/项目实战\"}]},{\"text\":\"Vue\",\"collapsed\":true,\"items\":[{\"text\":\"Vue3进阶\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3进阶\"},{\"text\":\"Vue3高级\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3高级\"},{\"text\":\"Vue3新语法\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3新语法\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/3、Vue/Vue2/Vue2项目\"}]},{\"text\":\"小程序\",\"collapsed\":true,\"items\":[{\"text\":\"小程序基础\",\"link\":\"/1、学前端/5、小程序/微信小程序\"},{\"text\":\"小程序优化\",\"link\":\"/1、学前端/5、小程序/小程序优化\"},{\"text\":\"uniapp\",\"link\":\"/1、学前端/5、小程序/uniapp\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/5、小程序/小程序项目\"}]}]},{\"text\":\"计算机基础\",\"collapsed\":true,\"items\":[{\"text\":\"数据结构\",\"link\":\"/计算机基础/数据结构/基础篇\"},{\"text\":\"操作系统\",\"link\":\"/计算机基础/计算机基础/操作系统\"},{\"text\":\"设计模式\",\"link\":\"/计算机基础/设计模式/基础篇\"},{\"text\":\"计算机网络\",\"link\":\"/计算机基础/计算机网络/网络基础\"},{\"text\":\"UML\",\"link\":\"/计算机基础/设计模式/UML\"},{\"text\":\"LeetCode\",\"link\":\"/计算机基础/算法/LeetCode\"}]},{\"text\":\"项目实战\",\"collapsed\":true,\"items\":[{\"text\":\"云尚办公\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/云尚办公/基础篇\"}]},{\"text\":\"小兔鲜\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/小兔鲜/基础篇\"},{\"text\":\"进阶篇1\",\"link\":\"/项目实战/小兔鲜/进阶篇1\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/小兔鲜/进阶篇2\"}]},{\"text\":\"地图\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/百度地图/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/百度地图/进阶篇\"}]},{\"text\":\"苍穹外卖\",\"collapsed\":true,\"items\":[{\"text\":\"进阶篇\",\"link\":\"/项目实战/苍穹外卖/进阶篇\"}]},{\"text\":\"黑马头条\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/黑马头条/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/黑马头条/进阶篇\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/黑马头条/进阶篇2\"},{\"text\":\"高级篇\",\"link\":\"/项目实战/黑马头条/高级篇\"}]},{\"text\":\"支付\",\"link\":\"/项目实战/支付\"},{\"text\":\"项目推荐\",\"link\":\"/项目实战/项目推荐\"}]},{\"text\":\"团队成员\",\"link\":\"/team\"}],\"siteTitle\":\"任硕的文档\",\"logo\":\"/Vue.png\",\"nav\":[{\"text\":\"Java学前端\",\"items\":[{\"items\":[{\"text\":\"HTML+JS\",\"link\":\"/Java学前端/HTML+JS\"},{\"text\":\"CSS\",\"link\":\"/Java学前端/CSS\"},{\"text\":\"Vue2+组件\",\"link\":\"/Java学前端/Vue2+组件\"},{\"text\":\"Vue3+组件\",\"link\":\"/Java学前端/Vue3+组件\"},{\"text\":\"React\",\"link\":\"/Java学前端/React\"}]}],\"activeMatch\":\"/Java/\"},{\"text\":\"软件测试\",\"items\":[{\"items\":[{\"text\":\"测试基础\",\"link\":\"/软件测试/测试基础\"},{\"text\":\"压力测试\",\"link\":\"/软件测试/压力测试\"}]}]},{\"text\":\"多线程\",\"items\":[{\"items\":[{\"text\":\"基础篇\",\"link\":\"/并发 & 多线程/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/并发 & 多线程/并发完善\"}]}]},{\"text\":\"开发工具\",\"items\":[{\"items\":[{\"text\":\"Chrome\",\"link\":\"/IDEA/Chrome\"},{\"text\":\"IDEA基础\",\"link\":\"/IDEA/IDEA基础\"},{\"text\":\"IDEA插件\",\"link\":\"/IDEA/IDEA插件\"},{\"text\":\"VS Code\",\"link\":\"/IDEA/VS Code\"}]}]},{\"text\":\"消息中间件\",\"items\":[{\"items\":[{\"text\":\"RabbitMQ\",\"link\":\"/消息中间件/RabbitMQ\"},{\"text\":\"RocketMQ\",\"link\":\"/消息中间件/RocketMQ\"},{\"text\":\"Kafka\",\"link\":\"/消息中间件/Kafka\"},{\"text\":\"Canal\",\"link\":\"/消息中间件/Canal\"}]}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/renshuo123/renshuo123.github.io\"},{\"icon\":\"twitter\",\"link\":\"#\"},{\"icon\":{\"svg\":\"<svg t=\\\"1676028692954\\\" class=\\\"icon\\\" ...</path></svg>\"},\"link\":\"https://github.com/\"}]},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>